皆さん こんにちは
ラズピコ研究員の moon です。
この記事は「初心者必見! Raspberry Pi Picoの C/C++デバッグ環境を容易に構築する」によって環境構築していることを前提にしています。
今回は Flashメモリー を定数の保管場所として読み書きしてみました。
USB-CDCとのコラボ機能の実装になっていますので、ぜひ動かして試して頂きたいです。
本プロジェクトの概要
Flashメモリーはプログラムの格納用として使われますが、電源が落ちても記憶しておく定数の格納用として使うこともできます。
ラズピコのFlashメモリーは2Mバイト(2 * 1024 * 1024 = 2,097,152バイト)の容量です。
書き込みはセクター単位で行われ、そのサイズは4,096バイトです。
今回は2Mの容量のうちの最後のセクターを定数の領域として読み書きしてみます。
(プログラムサイズを最大限、使えるようにするためです)
USB-CDCの通信を使ってPCからラズピコに簡単なコマンドを送り、コマンド形式が正しければ OK を返信して定数に値を書き込みます。
正しくなければ NG を返信します。
コマンド形式が正しかった場合には uart を使って各定数の値を標準出力します。
接続
UART を使うにはPicoProbeとラズピコを以下のように接続する必要があります。
これはPicoProbeのUSBシリアル機能とラズピコ(マイコンRP2040)のUARTをクロス接続するものです。
USB-CDCで通信する他、設定値を UART で printf()出力するため以下のように接続する必要があります。

新規プロジェクトを作成する
VSCodeを起動し、フォルダを開いている場合には ファイル – フォルダーを閉じる を選択します。
次にアクティビティーバーから Raspberry Pi Pico Project を選択し、サイドバーの New C/C++ Project を選択します。

Name は flash_access とし、Board type で Pico を選択します。
後は Studio support の Console over UART にチェックを入れます。
今回はC++でコードを書きます。
code generation options の Use project name as entry point file name と Generate C++ code にチェックを入れます。
Debugger は DebugProbe(CMSIS-DAP)[Default] を選択し、CMake Tools の Enable CMake-Tools extension integration にチェックを入れます。
そして右下の Create ボタンを押します。

キットの選択
キットはビルドツールと考えれば良いでしょう。
flash_access のキットを選択してください と言われるので、その下に出て来る候補の一番下の 「Pico コンパイラの使用: C = C:\Users…」を選択します。
実行とデバッグ
アクティビティーバーの実行とデバッグを選択します。
メニューの 実行 – デバッグの開始を選択します。
flash_access の起動対象を選択します と言われるので、その下の候補から flash_access を選択します。
main()関数の中の stdio_init_all() のところでプログラムが停止するので、F5キーを押してプログラムが動作することを確認しておきます。
確認後、Shift + F5キーを押してプログラムを停止しておきます。
シリアルモニター
シリアルモニタ ーは Tera Term の簡易版と考えれば良いと思います。
Raspberry Pi Picoの拡張を入れたら自動的にインストールされるようです。
エディター下の、下部パネルの右の方にあるシリアルモニタ ーを選択します。

ポートで正しいCOMポートを選択し、ボーレートを115200に設定します。
(歯車アイコンを選択すると、データビットやパリティを選択することができますが今回はデフォルト値のまま動くようなので設定不要です)
歯車アイコンを選択して設定内容だけ確認しておきましょう。
今回の設定値は 115200bps, データ:8ビット, パリティ:なし, ストップ:1ビット です。
確認後「監視の開始」を選択しておきます。
printf()による標準出力の結果をこちらで確認することができます。
ソースコード
構成する各ファイルをここで説明するのはたいへんです。
GitHubにプロジェクトをアップしますので こちら を参考になさってください。
今回はC++でプロジェクトを作成してみました。
ファイルをいくつかに分割していますので、それぞれについて簡単に説明します。
flash_access.cpp
main()関数のあるソースコードです。
while()ループに入る前に各定数の値を UART の printf() で出力します。
ループ内ではUSB-CDC通信のポーリングを行い、PCからのコマンドに応答します。
FlashAccessor.cpp
フラッシュメモリーの読み書きをするクラスです。
サンプルコードの こちら をカスタマイズしてつくりました。
ほぼサンプルのラッパークラスです。
UsbCDC.cpp
USB-CDC通信するクラスです。
TinyUSBのサンプルコードの こちら をカスタマイズしてつくりました。
StringParser.cpp
コマンド文字列の解析用につくったクラスです。
Stack.cpp
スタック構造にデータを格納するためのクラスです。
必要最小限の機能だけを実装しました。
Tera Termを使った場合等で、← や → キーを使うと画面に表示が残るためユーザーはその値が残っている(送信したもの)と思ってしまいます。
そこで文字を入力した後、←(左矢印)キーまたはback spaceキーを押したら、押された回数分だけ値をスタックに退避させておきます。
そして、→(右矢印)キーが押された場合に退避した値を復帰させることにしました。
もしスタックに値が積まれている状態で、通常のキーが押されたらその位置に新しい値を上書きし、スタックをpop()してスタックの値を捨てます。
必要以上に→(右矢印)キーを押すとスタックの値をpop()しきってしまいます。
そして画面の右の方にカーソルが移動してしまうため、その場合には半角スペースを追加することにしました。
ソースコードの要所にはコメントを記載していますので参考になさってください。
フォーマッター
今回は clang-format を使ってみました。
Windows11で使う場合、LLVMをインストールするのが簡単なようです。
PowerShellを管理者権限で起動し、以下のコマンドを入力します。
winget install llvm
C:\Program Files\LLVM\bin に clang-format.exe があることを確認します。
本プロジェクトの .vscode\settings.json にパスと各設定を記述しておきます。
これでソースコードを編集・保存した際に、いちいちフォーマットを手で調整する必要がなくなります。
自分好みのスタイルに合わせこむまでがたいへんそうですけど、これは便利ですね。
「塵も積もれば山」です。面倒くさがらずに、ぜひ設定してみてください。
動作確認
printf()出力は UART の標準出力を使います。
VSCodeのシリアルモニタ ーを使えば良いでしょう。
USB-CDC通信のPC側は Tera Term を使います。
ラズピコの方のプログラムを動かさないと、Tera Term側が重くなりますので、まずラズピコのプログラムを動作させておきます。
ラズピコが起動すると各定数の値を printf() 出力します。
以下は設定された値をシリアルモニタ ーで表示した例です。

ラズピコが起動すると、USB-CDC通信が認識されて Tera Term の「新しい接続」に表示されるシリアルポートが増えます。
USB-CDC通信の場合、シリアルポートが2つ見えますので、若い番号のCOMポートを選択してください。
ローカルエコーにチェックを入れて、改行コードは受信、送信ともに CR+LF を選択します。

コマンド
今回はFlashに保存する定数を、ID、 パスワード、int型の値、double型の値の4項目にしました。
コマンドは先頭に # をつけて、その後項目名を続けて書きます。
項目名は id , password , int , double です。
(1)IDの設定方法
#id 12345678 の12文字に CR LF を付加した14文字を送信します。
(idの後に半角スペースを入れる必要があります)
設定値は 12345678 の部分で8文字固定です。
(2)パスワードの設定方法
#password abcd1234 の18文字に CR LF を付加した20文字を送信します。
(passwordの後に半角スペースを入れる必要があります)
設定値は abcd1234 の部分で8文字固定です。
(3)intの設定方法
#int 12345 のように #int の後に半角スペースを入れた後に数値を入れて CR LF を付加して送信します。
設定値は 2,147,483,647~-2,147,483,648 の範囲で受け付けます。(符号付き32ビットの範囲)
(4)doubleの設定方法
#double 345.678 のように #double の後に半角スペースを入れた後に小数点を含んだ数値を入れて CR LF を付加して送信します。
設定値は 相当大きな数まで受け付けてくれますので試してみてください。
ラズピコ側で正しく受け取ると OK を返してきます。
そしてその値をFlashメモリーに書いた後、読み直して printf() 出力します。
実際に Tera Term で通信した時の画像を以下に貼っておきます。

定数の容量など
今回の仕様では、1セクタ内に収めて、書き込みサイズを4096固定にするために構造体を2重構造にしました。
そのため実際に定数として使える容量は 4096 – 1 で 4095 バイトになります。
構造体についてはプロジェクト内にある PaddedData.h を参照すればご理解頂けると思います。
ID、パスワード、int、doubleの値が格納されるのは ConfigData 構造体になります。
キーボードのUI
そこそこ手入れをしてみたのですが、キーボードのUI周りは難しいですね。
細かい動作確認までは行っていませんのでバグが見つかるかも知れませんがご容赦ください。
ライセンス
USB-CDC や Flash メモリーにアクセスするコードはSDKのサンプルを使わせて頂きましたので、プロジェクトのトップにライセンスファイルを置いています。
免責
本プロジェクトの目的はFlashメモリーの読み書きです。
問題ないと思いますが私の方で動作保証は致しかねますので、充分検証を行った後ご自身の責任でお使いください。
最後に
Flashメモリーの読み書きが主な目的だったのですが、キーボードのUIにかなり手こずり、そちらの方にかなりの時間を費やしました。
ただ、それなりにお勉強になりました。
いかがでしたか、皆さまはFlashメモリーの読み書きが確認できましたか。
お疲れさまでした。