2023年02月04日

メモリ空き領域確認方法 PICO-SDK版

以前にSW4STM32環境でのメモリ領域を確認方法を紹介しましたが、今回はRP2040のPICO-SDK環境でビルド時にメモリ領域を確認する方法を紹介します。

簡単なプログラムであれば、FlashやRamの領域を気にする必要はありませんが、大量にメモリを使用する場合はどれくらい既に占有しているのか気になると思います。リンカの設定を少し追加することで詳細情報をビルド時のコンソールに表示することが可能です。

デフォルトではFlashやRamの領域の情報は表示されません。表示させる場合はプロジェクトフォルダ内の「CMakeLists.txt」のtarget_link_libraries以降に下記のスクリプトを追記します。下記のスクリプトのPROJECT_NAMEの部分はプロジェクトに応じて変更してください。

target_link_options(PROJECT_NAME PRIVATE "LINKER:--print-memory-usage")

実際にプロジェクト名がProjectionBallの場合で追加した際のイメージは下記の通りです。

option_image.png


追記すると下記のようにビルドの度にFLASHとRAMの占有率が表示されるようになります。

Memory region Used Size Region Size %age Used
FLASH: 43380 B 2 MB 2.07%
RAM: 79212 B 256 KB 30.22%
SCRATCH_X: 2 KB 4 KB 50.00%
SCRATCH_Y: 0 GB 4 KB 0.00%

なお、STM32等にはない、SCRATCH_X、SCRATCH_Yの領域はマルチコア利用時の振り分けに使用される領域なようです。


memory_usage.png


RP2040でも大量にメモリを使用するプロジェクトの場合にはぜひ、このような設定を有効化してみてください。
posted by Crescent at 00:00| Comment(0) | TrackBack(0) | 組込ソフト | このブログの読者になる | 更新情報をチェックする

2022年11月26日

組込系機械学習ライブラリ

今回はマイコン等に組込可能な機械学習ライブラリを調査してみました。マイコン等の組込系で使用するため、C/C++で利用可能な代表的なライブラリの特徴を調べてみました。

 最も良く使用される組込系機械学習ライブラリです。ただ、組込系の場合、ARMのライブラリと依存関係があるため、ARM以外のPICやAVRといったCPUではそのままでは利用できません。RISCV等をターゲットにしたARM以外に実装した例もありますが、ライブラリが非常に大きく、ポーティングに難ありなようです。

 STM32マイコンに実装する場合にCubeMXと統合されたUIで利用できる機械学習ライブラリです。KerasやTensorFlow等の学習結果を簡単に組み込むことが可能です。また、学習結果の圧縮やテスト等が容易にできるため、STM32マイコンであれば非常に便利です。一方でSTM32マイコン以外では使用できなく、昨今の半導体不足の影響をモロに受けているため、当面は安定した入手が難しい可能性があります。

 scikit-learnもしくはKerasの学習結果をC/C++に変換することができます。Pythonで学習結果を読み込ませると自動的にC言語でヘッダーファイルが生成され、そのままマイコンのプロジェクトソースに組み込むことが可能です。1つのヘッダーファイルをプロジェクトソースに組み込むだけて利用できるため、他のライブラリのように複数のソースコードをプロジェクトに追加する必要もなく、非常に簡単に組み込むことが可能です。また、ライブラリ自体非常に軽量なため、小規模なモデルであれば8ビットマイコン等にも組込可能です。ただし、利用可能なモデルに制約があります。

ELL
 マイクロソフトが提供する組込向けの機械学習ライブラリです。主にC++で実装されています。組込向けといってもマイコン等ではなく、raspberry piといったSBC等をターゲットにしているようです。ここ数年の開発ペースは落ちているようです。

その他

DLib
FANN

 実際にSTM32 Cube AI、Tensorflow Lite、emlearnを使ってみました。印象として、ターゲットとなるマイコンでサンプルがあれば、Tensorflow Liteはネット上に情報が多く、利用しやすいと思いました。初心者でも簡単に効率よく、推論結果を評価したりできる点ではSTM32 Cube AIがお勧めです。また、利用可能な機械学習モデルに制約があるものの、どのようなマイコンにも簡単に組み込むことができ、C言語で移植性が高いという面ではemlearnがお勧めでです。個人的にはSTM32、RP2040、PIC32マイコン等の様々な環境で利用することを想定し、今後はemlearnをより使ってみたいと思いました。
posted by Crescent at 00:00| Comment(0) | TrackBack(0) | 組込ソフト | このブログの読者になる | 更新情報をチェックする

2022年05月07日

PIC32 C++プロジェクト

今回はPIC32マイコンでC++ (CPP) プロジェクトを作成する方法について紹介します。といっても記事にする程でないほど簡単でした。

STM32マイコンのSW4STM32やCubeIDEではC++プロジェクトへの変換作業等が必要でしたが、MPLAB X(v5.45) + XC32(v2.50) +Harmony3では特に変換作業等必要なく、cppファイルと.hppファイルを追加するだけでした。また、ライブラリやプロジェクト、コンパイラ等はC++に対応済のため、追加設定は不要です。そのため、非常に簡単に実装できます。

追加するcppファイルと.hppファイルとして、ラッパーとなるwrapper.cpp、wrapper.hpp、LED点滅用の関数LedBlink.cpp、LedBlink.hppをプロジェクトに追加します。また、app.cからラッパー関数を呼び出すためのcpploop();を追加しました。各ファイルの詳細についてはこちらにアップロードしたため、割愛します。

通常のプロジェクト同様にLedBlink.cpp内でブレイクポイントを置いてデバッグもできました。

PIC32CPP.JPG

思った以上にすんなりC++ (CPP) プロジェクトを動かすことができたため、今後はパワフルなPIC32マイコンを活かして、機械学習系のライブラリ等にも応用してみたいと思います。
posted by Crescent at 00:00| Comment(0) | TrackBack(0) | 組込ソフト | このブログの読者になる | 更新情報をチェックする

2022年03月12日

PIC32 ウォッチドッグタイマ

 今回はPIC32マイコンのWDTの設定方法を紹介します。WDT(ウォッチドッグタイマ)は名の通り、MPUの動作を見張る番犬です。WDTを有効化するとMPUに異常な処理が発生した場合や意図しない処理の無限ループに入ってしまった場合に異常としてMPUをリセットさせることができます。PIC32マイコンにはWDTの他にDMT(デッドマンタイマ)も搭載されています。目的と用途が異なるため、ここでは詳細は省略しますが、WDTはスリープ等からの復帰にも使用でき、汎用的でざっくりとした時間間隔での監視が可能です。一方、DMTはスリープ復帰には使用できませんが、設定した命令数(処理)に対して細かく監視間隔を設定できます。DMTは少し特殊な用途となるため、今回はWDTのみ紹介します。

 WDTの動作原理として、監視の時間間隔を予め設定し、監視を開始します(WDT_Enable)。そのあと、コード上で定期的にWDTカウントリフレッシュ関数WDT_Clearを呼び出します。正常な場合は予め設定した監視時間よりも前にWDT_Clear関数で正常に動いていることをWDTに知らせます。何かしらの異常が発生した場合は予め設定した監視時間になってもWDT_Clear関数による知らせがWDTにないため、監視時間を超えた時点でWDTが強制的にMPUのリセットを実行する仕組みです。正常動作にも関わらず、監視時間に達してリセットされてしまうということがないように、ある程度余裕のある監視時間を設定すべきです。ただ、余裕にしすぎると万一、異常な状態になった場合にリセットがかかるまでに時間を要することになるため、バランスを見て設定する必要があります。例えば、長い処理ではリフレッシュ関数を所々に予め入れておくといった対応が想定されます。

Harmoney3のProject GraphのSystem項目から設定することができます。


wdt0.jpg

WDTの設定については特に分かりずらく、WDTのパラメータ設定はDEVCFG1から設定します。WDTPSのパラメータを変更することでリセットまでの監視時間を変更することが可能です。

wdt1.jpg

 一方、WDTの有効、無効はDEVCFG1とは別のWDTの項目にチェックを入れることで自動的にWDT関連の関数ライブラリコードが生成されるようになります。WDTPSのパラメータの設定を秒数としてWDT項目から確認することができます。

wdt2.jpg

 パラメータ設定DEVCFG1と有効可否設定WDTが分かれているため、初めてだと戸惑いました。WDTの有効、無効は他のペリフェラル機能と同様にAvailable Componentsに項目を入れた方が直感的で分かりやすいと思いました。
posted by Crescent at 00:00| Comment(0) | 組込ソフト | このブログの読者になる | 更新情報をチェックする

2022年02月26日

PIC32MZEFシリーズのブートローダ機能

 PIC32MZ2048EFGマイコンのブートローダ機能を検討したため、今回はその際に戸惑った点等を備忘録として紹介します。ブートローダ機能を利用するとPICkit4やSNAP等の専用の書き込み治具がなくても、SDカードやUART等からファームウェアを容易に書き換えできるようになります。何かしらの製品に組み込んだ際にユーザ側でファームアップデートすることが想定される場合に便利です。今回は事前にブートローダを書き込んだPIC32MZマイコンにファームウェアの入ったSDカードを挿入すると自動的にファームウェアが書き込まれるブートローダを作成しました。Microchipから様々なブートローダのドキュメントが提供されていますが、いまいち全容を把握するのに苦労したため、ポイントを絞って紹介したいと思います。詳細は各ドキュメントを参照してください。


まずはブートローダ機能を開発する際のポイントを先に紹介します。

■ポイント
@ブートローダ用のプロジェクトとアプリケーションのプロジェクトは分けて作成する
 →リンカファイルが異なるため、ミスを減らすためにプロジェクトを分ける。また、アプリケーション用のプロジェクトでは通常のバイナリ(hex)ファイルの他にbinファイルを生成するスクリプトを追加することでブートローダ読み込み用のbinファイルを追加で生成させる。

Aリンカファイル作成方法
 →Harmony3+bootloaderで生成したプロジェクトでブートローダ用のリンカファイルbtl.ldはそのまま使用可能。一方、アプリケーション側のリンカファイルはp32MZ2048EFG100.ldを編集必須。また、Harmony3+bootloaderで生成したプロジェクトのリンカ設定はbtl.ldファイルでなく、p32MZ2048EFG100.ldファイルとなっているため、p32MZ2048EFG100.ldをプロジェクトから除外してブートローダ用のリンカファイルbtl.ldに置き換えること。

Bクロック設定やデバイスコンフィグは同じ設定にする
 →ブートローダとアプリケーションの切り替え動作が不安定になる。

Cブートローダ用のプロジェクトは最低限の機能に絞る
 →機能を盛り込むとブートローダファームがブートローダ領域に入らない。SDを読み込み専用に設定し、コンソールデバッグ機能は使用しない。

Dブートローダのファームは直接書き込み可能
 →MPLAB IDEからデバッガを介して書き込み可能。既定ではフラッシュ全削除後に書き込みされるため、通常は書き込み直後にブートローダが起動し、アプリケーションの書き込みモードに入る。

Eアプリケーションのファームは直接書き込まずにブートローダから書き込み
 →直接書き込むとフラッシュ全削除してアプリケーションだけが書き込まれる。ブートローダが消されてしまうため、アプリケーション領域に処理をジャンプさせることができず、アプリケーションが起動しない。

■ブートローダ機能のシーケンス
ブートローダ起動→トリガチェック→(書き換えモードの時)ファーム書き換え処理→ソフトリセット
                →(通常起動の時)アプリケーション起動処理→アプリケーション起動

■トリガ種類
ブートローダが起動後にファーム書き換えモードに入るか、通常のアプリケーション起動モードに入るかはIO状態やメモリ上の変数状態で切り替えることができます。

・a)IO状態トリガ
 PIC32マイコンをリセットさせて、起動時のIO状態を見て切り替えます
・b)メモリ上の変数状態トリガ
 アプリケーションが起動している状態でユーザ操作によってファーム書き換えモードにします。ファーム書き換えモードでは特定のメモリ領域に変数を書き込んで部分的なシステムリセット(特定のメモリ領域はリセットされない)をかけることでブートローダを再度起動させて、特定のメモリ領域の変数を見て書き換えモードに入るか、通常のアプリケーション起動モードに入るか切り替えます。




■ブートローダ側の開発流れ
1. MPLAB ] IDEのHarmony3にBootloaderパッケージを追加する。
 Tools→Embedded→MPLAB Harmoney3 Content Managerをクリック。bootloaderとbootloader_apps_sd〜にチェックを入れてパッケージを追加します。

bootloader1.jpg

bootloader2.jpg


2. Harmoney3プロジェクトを作成し、Filesytemタイプのbootloaderを追加する。
 メディアタイプにSDカードを選択し、b)メモリ上の変数状態トリガを有効にするために16バイトの領域を確保する。また、ファイルシステムの設定は自動マウントを有効化して、読み込み専用に設定する。また、32GB以上のSDカードにも対応させる場合はexFatにチェックを入れる。また、クロック設定やデバイスコンフィグはアプリケーション側と共通の設定をします。

bootloader3.jpg

bootloader4.jpg

bootloader5.jpg


3. コード生成後にリンカファイルを設定する。
 Harmoney3プロジェクトでbootloaderを追加すると自動的にbtl.ldとp32MZ2048EFG100.ldの2つのリンカファイルがプロジェクトに追加される。ただ、ビルド設定ではp32MZ2048EFG100.ldが有効となるため、p32MZ2048EFG100.ldをプロジェクトから除外して、btl.ldだけにする。

bootloader7.jpg


4. ファイルシステムコード追記する。
 デフォルトではff.hのビルドに失敗するため、ff.hの38行目くらいに#define __STDC_VERSION__ 199902を定義する。

5. ブートローダコードを実装する。
 詳細はコードをアップロードしてありますのでそちらを参照してください。起動直後にブートローダ機能を実行するか、アプリケーションを起動させるかの切り替えがinitialization.cにあります。

■アプリケーション側の開発流れ
1. 通常通りにMPLAB ] IDEのHarmony3のプロジェクトを作成します。また、クロック設定やデバイスコンフィグはブートローダ側と共通の設定をします。また、リンカファイルを変更して独自のリンカファイルを使用するため、Harmony3のプロジェクトグラフ内のsystem→Device&Project Confguration→Toolchain selectionのAdd linker file to projectのチェックを外します。

bootloader9.jpg

2. リンカファイルp32MZ2048EFG100.ldを書き換えます。

・PROVIDE(_ebase_address = 0x9D000000);の下にPROVIDE(_ebase_vector_offsets = 0x1000);を追加。
・_RESET_ADDR = 0xBFC00000;を_RESET_ADDR = 0xBD000000;に変更。
・_BEV_EXCPT_ADDR = 0xBFC00380;と_DBG_EXCPT_ADDR = 0xBFC00480;を削除。
・_SIMPLE_TLB_REFILL_EXCPT_ADDR、_CACHE_ERR_EXCPT_ADDR 、_GEN_EXCPT_ADDR に_ebase_address を追加して下記のように書き換える。
_SIMPLE_TLB_REFILL_EXCPT_ADDR = _ebase_address + _ebase_vector_offsets + 0;
_CACHE_ERR_EXCPT_ADDR = _ebase_address + _ebase_vector_offsets + 0x100;
_GEN_EXCPT_ADDR = _ebase_address + _ebase_vector_offsets + 0x180;

・メモリ領域(MEMORY)の書き換えとconfig領域の削除
(変更)
kseg0_program_mem (rx) : ORIGIN = 0x9D001000, LENGTH = 0x200000 - 0x1000
kseg1_boot_mem : ORIGIN = 0xBD000000, LENGTH = 0x480
kseg1_boot_mem_4B0 : ORIGIN = 0xBD0004B0, LENGTH = 0x1000 - 0x04B0
(追記)
/* Reserve 16 Bytes to Store Bootloader Trigger Pattern */
kseg0_data_mem (w!x) : ORIGIN = 0x80000000 + 16, LENGTH = 0x80000 - 16
(削除)
アプリケーション側ではコンフィグを行わないため、config領域を削除します。
config_BFC0FF40からboot2lastpageまでを削除します。

・SECTION領域(SECTIONS)のconfig削除
.config_BFC0FF40から始まるSECTIONSを削除する。

・SECTION領域(SECTIONS)の例外処理を削除
ブートローダ側に含まれるため、下記の例外処理を削除する。
.bev_excpt _BEV_EXCPT_ADDR :
{
KEEP(*(.bev_handler))
} > kseg1_boot_mem

・割込みオフセットに_ebase_vector_offsetsを追記

* Interrupt vector table with vector offsets */
.vectors _ebase_address + _ebase_vector_offsets + 0x200 :

・ブートローダ側に含まれるため、下記を削除する
/* The startup code is in the .reset.startup section.
* Keep this here for backwards compatibility with older
* C32 v1.xx releases.
*/
.startup ORIGIN(kseg0_boot_mem) :
{
KEEP(*(.startup))
} > kseg0_boot_mem

・ デバッグ例外処理とコンフィグはブートローダ側に含まれるため、除く処理を追加する。
/DISCARD/ : { *(.note.GNU-stack) *(.gnu_debuglink) *(.gnu.lto_*) *(.discard) }の下に下記を追加する。
/DISCARD/ : { *(._debug_exception) }
/DISCARD/ : { *(.config_*) }

最終的に書き換え前(書換前リンカファイル.ld)と書き換え後(書換後リンカファイル.ld)のファイルはこのようになります。

3. アプリケーション側で必要に応じて、ソフトウェア的にファーム書き換えモードにするコードを追加します。BTL_TRIGGER_PATTERN で定義された特殊な値をBTL_TRIGGER_RAM_START に書き込んでソフトリセットさせることでリセット後にブートローダが起動し、SDカードからファームを書き換える処理を走らせることができます。

#include "sys/kmem.h"

#define BTL_TRIGGER_RAM_START KVA0_TO_KVA1(0x80000000)
#define BTL_TRIGGER_PATTERN (0x5048434DUL)
#define DCACHE_CLEAN_BY_ADDR(start, sz)
static uint32_t *ramStart = (uint32_t *)BTL_TRIGGER_RAM_START;

SYS_DEBUG_PRINT(SYS_ERROR_DEBUG, "Bootloader Triggered!\r\n");
ramStart[0] = BTL_TRIGGER_PATTERN;
ramStart[1] = BTL_TRIGGER_PATTERN;
ramStart[2] = BTL_TRIGGER_PATTERN;
ramStart[3] = BTL_TRIGGER_PATTERN;
DCACHE_CLEAN_BY_ADDR(ramStart, 16);
APP_SystemReset();

4. プロジェクト設定でbinファイルを生成するコードを追加します。
アプリケーション側のビルド後にhexファイルからbinファイルを生成します。
${MP_CC_DIR}/xc32-objcopy -I ihex -O binary ${DISTDIR}/${PROJECTNAME}.${IMAGE_TYPE}.hex ${DISTDIR}/${PROJECTNAME}.${IMAGE_TYPE}.bin

bootloader8.jpg


これでブートローダ機能の設定および実装は完了です。先にブートローダ側のファームをPIC32マイコンに書き込んで、アプリケーション側のbinファイルをimage.binにファイル名を書き換えてSDカードに入れるとファームが書き換えられ、アプリケーションが実行されます。プロジェクトファイルおよび全体のコードはこちら(code.zip)です。

なお、パッケージを追加するとC:\Users\(ユーザ名)\Harmony3\bootloader_apps_sdcard\apps\sdcard_bootloader内にブートローダ側のbootloaderとアプリケーション側のtest_appがサンプルコードが追加されます。ただ、サンプルプログラム(PIC32MZDA)とREADMEだけでは情報少なく苦労したため、試行錯誤しながら何とか動かすことができました。SDカード以外にもUARTやフラッシュメモリ等からも書き換えできますが、専用ソフトが不要でユーザ側のOS環境に依らず負担が少ないSDカードからの書き換えが汎用性が高く良いと思いました。また、アプリケーション側のリンカファイルを書き換えるとそのままでは簡単にデバッグやブートローダ無の単体動作できないため、元のリンカファイルも残しておいて、読み込むリンカファイルを切り替えるとよいと思います(Lodableに追加する別のデバッグ方法もありますが...)。
posted by Crescent at 00:00| Comment(0) | 組込ソフト | このブログの読者になる | 更新情報をチェックする