2024年07月20日

pico-sdkディレクトリ変更時のポイント

今回はRP2040でpico-sdkディレクトリを変更した際に忘れやすいポイントを覚書として紹介したいと思います。

通常、コードを変更してビルドする場合やPico Project Generatorで生成したプロジェクトの場合はbuildディレクトリに移動してmakeするだけです。一方でpico-sdkのディレクトリを変更した場合はCMakeLists.txt内のset(PICO_SDK_PATH "???/pico-sdk")を更新してもディレクトリが反映されず、古いディレクトリを参照してしまったり、pico-sdkのバージョン違いのエラーが発生してビルドに失敗する場合があります。パスをexport PICO_SDK_PATH=???/pico-sdkのように追加しても失敗する場合があります。

このような場合はビルドディレクトリに移動後、makeする前にでcmake ..を実行し、ビルド環境を再構築する必要があります。

普段はmakeのみでビルドできますが、pico-sdkディレクトリ等の環境を変更した場合はcmake ..のビルド環境の再構築が必要です。普段は再構築し直す必要がないため、忘れがちです。久しぶりだとそれに気づかず、ビルドが通らない原因の調査に時間を要してしまいました。ポイントはcmake ..です。
posted by Crescent at 00:00| Comment(0) | TrackBack(0) | 組込ソフト | このブログの読者になる | 更新情報をチェックする

2023年11月11日

Web HID API

以前にUSBシリアルI2C変換基板とWebシリアルAPIを用いたツールを紹介しました。今回はWebシリアルAPIを応用してWeb HID APIを使用したツールを開発してみました。

Web HID APIはキーボードやマウス、ゲームパッド等のUSBヒューマンインタフェースと接続するためのAPIです。残念ならが、WebシリアルAPI同様に対応したブラウザはEdgeもしくはChromeのみ対応となっており、23年11月時点ではFirefoxやSafariは対応していません。Web HID APIはUSBヒューマンインタフェースと接続するためのAPIですが、USB-SPIコンバータ、MCP2210USB-I2CコンバータMCP2221等のHID APIに対応したUSBデバイスとWeb HID APIを介して通信することが可能です。

今回はUSB-SPIコンバータ、MCP2210とWeb HID APIでブラウザを介して通信するツールを実装してみました。Web HID APIの仕様に従って下記のようにMCP2210のベンダID、プロダクトIDからnavigator.hid.requestDeviceを実行するとデバイス選択画面が表示され、デバイスを選択できるようになります。


const vendor_id = 0x04D8;//Microchip Technology Inc.
const product_id = 0x00DE;//MCP2210 USB-SPI
[device] = await navigator.hid.requestDevice(
{ filters: [{'vendorId': vendor_id, 'productId': product_id}] }
)

WebHidApi_MCP2210_list.png


デバイス選択後にデバイスを下記のようにOpenし、受信データがあった際にイベント処理を実行するため、addEventListenerinputreportを登録します。
const resOpen = await device.open();
await device.addEventListener("inputreport", handleInputReport);

逆にデータをデバイス側に送信する場合はsendReportを用いてデータを送信します。
await device.sendReport(0, sendArry);


デバイス接続、送受信の他に一通りの機能を実装したツールのリンクはこちらです。MCP2210をお持ちであればブラウザを介して簡単に動作確認が可能です。すべてのコードはhtmlファイル内にまとめていますので、ページ内の右クリックでコードの表示から実装を確認することが可能です。

試しにWeb USB SPI ToolとMCP2210、NOR-SPIフラッシュメモリW25Q128JVを使ってフラッシュメモリの固有コードの読み出しをテストしてみました。コマンド0x90を実行すると0xEF、0x17とW25Q128JVの固有コードを読み出すことができました。

WebHidApi_MCP2210.png

今回はWeb HID APIとMCP2210を用いてフラッシュメモリと通信してみました。今後はWeb HID APIを用いた応用的な機能を開発して順次公開したいと思います。
posted by Crescent at 00:00| Comment(0) | TrackBack(0) | 組込ソフト | このブログの読者になる | 更新情報をチェックする

2023年10月07日

RP2040のBrown-out Reset

今回はRaspberry Pi Picoに搭載されるRP2040のBrown-out Reset(BOR)の設定方法について紹介します。BORは電源投入時や急激な負荷変動等で電源が不安定になった場合にマイコンを強制的にリセットさせることが可能です。電源が不安定になった際にマイコンをリセットさせないと意図しない処理が行われたり、初期化処理が正しく行われないということが生じます。RP2040のBORはデフォルトで0.860Vの設定がされているため、特別な理由がない限りは設定変更は不要です。電源変動が大きい環境で使用する場合などで動作を安定化させる際に必要に応じて変更します。

RP2040のCPUのコア電圧はデフォルトで1.1Vとなっています。これに対して、BORの設定はデフォルトで0.860Vとなっています。BORの設定はコア電圧よりも少し低い電圧に設定する必要がありますが、近づけすぎると少しの電圧変動でも頻繁にリセットがかかってしまいます。逆にBORの設定電圧を下げすぎると、リセットはかからないものの、電圧変動によってマイコンの処理が正しく行われず、動作が不安定になる可能性が高くなります。そのため、デフォルトの0.860Vから下げて設定することは避けるべきです。なお、RP2040のCPUのコア電圧はデフォルトで1.1VはVREG_AND_CHIP_RESET_BASEのVREG_AND_CHIP_RESET_VREG_OFFSET に値が格納されています。


今回はデフォルトの0.860Vから1.032Vに上げる場合を紹介します。BOR関連の定義は下記のヘッダで定義されているため、ヘッダに追加します。
#include "hardware/structs/vreg_and_chip_reset.h"
#include "hardware/regs/addressmap.h"

BOR定義の構造体がヘッダ内で定義されているため、構造体を利用します。BORの電圧の抜粋は下記の通りです。

// 1001 - 0.860V (default)
// 1010 - 0.903V
// 1011 - 0.946V
// 1100 - 0.989V
// 1101 - 1.032V
// 1110 - 1.075V
// 1111 - 1.118V


下記のコードを入れ込むことで1.032Vに変更することが可能です。必要に応じて3行目の0b1101の部分を設定したい電圧に変更してください。

vreg_and_chip_reset_hw_t *vcr;
vcr = vreg_and_chip_reset_hw;
vcr->bod = (0b1101 << VREG_AND_CHIP_RESET_BOD_VSEL_LSB) | VREG_AND_CHIP_RESET_BOD_EN_RESET;


当然ですが、コア電圧が1.1Vのため、コア電圧よりも高い0b1111の1.118Vに設定するとその瞬間にリセットがかかります。RP2040のBORについて、あまり情報がなかったため、紹介しました。ロボット制御やモータ制御等の場合、モータの急激な動きで電源電圧が低下し、マイコンが不安定になる場合があります。そのような場合に電源やモータのコンデンサを強化することはもちろんですが、BORの閾値電圧を少し高めに設定することで安定化できる場合があります。
posted by Crescent at 00:00| Comment(0) | TrackBack(0) | 組込ソフト | このブログの読者になる | 更新情報をチェックする

2023年09月09日

RP2040で厳密なタイマ割込みを実現するための注意点

Raspberry Pi Picoに搭載されるRP2040は安価でPIOや264kBの大きなRAMと非常に魅力的なマイコンです。一方でSTM32マイコンやPICマイコンを使ったことがある経験者からすると、マイコン思想の違いからSTM32やPICと比べて思うように実装できないと感じることがあると思います。

今回はRP2040でRaspberry Pi Pico C/C++ SDKを使用した際の厳密なタイマ割込み(=ジッターが少なく、時間クリティカルな処理)を実現するために気を付けるべきポイントについて紹介します。

@タイマ実行コア
usec単位でのタイマ割込みを利用する際にadd_repeating_timer_usを使用することが多いと思います。ただ、add_repeating_timer_usはデフォルトでcore0で実行されるため、core1のタイマ割込みとしてadd_repeating_timer_usを使用するとcore0の処理の影響を受けてしまう可能性があります。例えば指定したusec単位での処理が間に合わないといった問題やジッターが生じて微小に割込みタイミングが前後するといった問題が生じます。

この問題を防ぐため、add_repeating_timer_usの代わりにalarm_pool_createとalarm_pool_add_repeating_timer_usを使用します。タイマを使用するコアからalarm_pool_create関数を実行することで、もう一方のコアの影響を受けずにタイマ割込みを行うことができます。

例えば、core1でタイマ割込みを利用する場合、multicore_launch_core1で呼び出す関数の処理の最初にalarm_pool_createを呼び出すことでタイマ割込みがcore1から実行されるようになります。

alarm_pool_t* core1Alarm = alarm_pool_create(0, 4);
alarm_pool_add_repeating_timer_us(core1Alarm, 100, timer_callback, NULL, &timer);

A関数RAM配置
RP2040はFlashを内蔵していないため、QSPI接続の外部Flashにアクセスしながら処理を実行します(XiP機能)。外部Flashは内蔵Flashに比べて速度が遅いため、usec単位でのタイマ割込みの処理中に外部Flashへのアクセスが発生すると大幅に処理が遅れます(1回で数10usec~)。Raspberry Pi Pico C/C++ SDKでは外部Flashへのアクセスを抑制するための手段が提供されています。外部Flashへのアクセスを抑制するため、usec単位でのタイマ割込みで処理する関数に__not_in_flash_funcマクロや__time_critical_funcマクロを使用します。

例えば void timer_callback(){・・・}という関数の場合、void __not_in_flash_func(timer_callback)(){・・・}という風に関数を書き換えることで関数をRAMに展開し、外部Flashへのアクセスを抑制することが可能です。詳細についてはここでは説明しませんが、platform.h内に当該マクロの定義と説明があります。

また、__not_in_flash_funcマクロや__time_critical_funcマクロの他にすべての関数をRAMに展開する方法もあります。ただ、RAMに入りきらない場合もあるため、すべてのケースで推奨される方法ではありません。すべての関数をRAMに展開するにはCMakeLists.txtの先頭から数行目に下記の設定を追加します。

set(PICO_COPY_TO_RAM,1)


BベクタテーブルRAM配置
割込みのベクタテーブルはデフォルトでRAM配置(PICO_NO_RAM_VECTOR_TABLE 0)となっているため、そのままの設定であれば注意する必要はありません。意図的にPICO_NO_RAM_VECTOR_TABLE 1に変更した際は割込み等で外部Flashへのアクセスが発生するため、意図せず遅れの原因になる可能性があるため、注意が必要です。


今回はRP2040で厳密なタイマ割込みを実現するために気を付けるべきポイントについて紹介しました。モータ制御や電流制御、音声処理等を行う場合、usec単位で細かくタイマ割込みを実現する必要があります。デュアルコアかつ外部FLASHから読み込みというRP2040固有の仕様からSTM32やPICとは違った注意が必要です。実際にSTM32から移植した際、デュアルコアにも関わらず、思ったようなパフォーマンスが出ないといった場面がありました。具体的にはあるモータ制御の処理を72MHzのSTM32F3マイコンでは100usec毎に処理を実行できていたにも関わらず、125MHzのRP2040では150usecに設定しないと処理が間に合わない状況でした。処理の実行時間をIO出力させてオシロで調べると最速で30usecで処理が終わっているものの、外部Flashへのアクセス等で時々100usecを超えてしまうことが分かりました。上記の設定を見直すことでRP2040のデュアルコアを生かして、STM32F3マイコンよりも高速に50usecで処理ができるようになりました。

他にもRP2040固有の気を付けるべきポイントがあるため、また別の機会に紹介したいと思います。
posted by Crescent at 00:00| Comment(0) | TrackBack(0) | 組込ソフト | このブログの読者になる | 更新情報をチェックする

2023年05月27日

pico-sdk 最適化オプション

RP2040をC言語で使用する場合にpico-sdk+pico-project-generatorを使用することが多いと思います。先日、pico-sdkを使用していて、意図通りにRP2040が動かないことがありました。この原因として最適化オプションが働いて意図せず、変数等が削除されてしまったことでした。多くはvolatile等のオプションを変数に付与することで解決しますが、プロジェクトが大きくなるとプロジェクト全体の最適化オプションを変更した方が楽な場合が多々あります。

今回はpico-sdk+pico-project-generatorでビルドのオプションを変更する方法について紹介します。多くの方法としては下記のようにcmakeの引数でビルドオプションを指定することが一般的ですが、毎回、ビルドの度に指定するのは面倒です。

cmake -DCMAKE_BUILD_TYPE=Debug -DPICO_DEOPTIMIZED_DEBUG=1
make -j4


pico-sdk+pico-project-generatoの場合、自動的にプロジェクトフォルダ内にCMakeLists.txtが生成されます。今回はプロジェクトフォルダ内のCMakeLists.txtにビルドオプションを書き込んで、ビルドオプション指定を自動化する方法を紹介します。
プロジェクトフォルダ内のCMakeLists.txtをテキストエディタで開き、先頭のset部分に下記のスクリプトを追加します。

set(CMAKE_BUILD_TYPE "Debug")
set(OPTIMIZATION_FLAG 1)

実際に書き込んだイメージは下記です。

option.jpg


なお、デフォルトは
set(OPTIMIZATION_FLAG "-Os")
になっているようでサイズ最適化のため、最適化オプションが働いて意図せず変数が削除される可能性があります。

急に意図通りにRP2040が動かなくなり、最初はpico-sdkのバージョンやcmakeのバージョン等が原因と思いましたが、結局、ビルドの最適化オプションが原因であると分かりました。eclipseベースの開発環境では簡単にビルドの最適化オプションを確認、変更できますが、cmakeベースでは気づきにくいため、注意が必要だと思いました。
posted by Crescent at 00:00| Comment(0) | TrackBack(0) | 組込ソフト | このブログの読者になる | 更新情報をチェックする