freeRTOSのユーザーコードを隔離する

STM32 シリーズですが、freeRTOSのユーザコードをできる限り自動生成されるコードから分離したい、というか移植性とか考えたらそれが自然

<実行環境>

・STM32F401re

・M4 MacBook Pro Tahoe

・CubeIDE 1.19.0

Core/IncとCore/Srcの下にprocというユーザコード用のディレクトリ作成、Inc/Srcの中ならばbuildはソースコードを見つけて実行してくれる

<やっていること>

defaultTaskはLEDの定期点滅、lcd_taskはst7789 LCDの表示処理を呼び出しているだけ、freeRTOSはpreemptiveなのでdafultTaskの実行が必要になればlcd_taskの実行を中断してLCD表示のtoggle処理をおこなく、処理時間は人間の時間感覚からは全くの瞬時だからLCD表示的には全く認識できないレベル

<task定義とそれを扱う仕組み>

① CubeMXで定義

lcd表示タスクは優先度を下げておく、ADC DMA結果を分析するタスクの方が優先順位高いよね普通は

Task Nameは②のTask_attributeで使われ、Entry Functionはfreertos.c中の関数名になります

② freertos.cでタスクの属性とタスクそのものの定義

③ freertos.cのタスク初期化(osThreadNew())で②の定義が使われ、Task(StartDefualtTask)等に紐付けされる

<ユーザコードの分離>

freertos.c中のコード、defaultTaskではボード上のLEDを点滅させてるだけ、StartTask03は実態はなくて、ユーザコードの呼び出しだけ

void StartDefaultTask(void *argument) {
  /* 生存確認(Lチカ)だけして大半は眠る */
  for(;;) {
    HAL_GPIO_TogglePin(GPIOA, LED_PIN);
    osDelay(500);
  }
}

/* USER CODE BEGIN Header_StartTask03 */
/**
* @brief Function implementing the lcd_Task thread.
* @param argument: Not used
* @retval None
*/
/* USER CODE END Header_StartTask03 */
void StartTask03(void *argument)
{
  /* USER CODE BEGIN StartTask03 */
  /* Infinite loop */
  for(;;)
  {
	lcd_process();  // LCD display process
    osDelay(1);
  }
  /* USER CODE END StartTask03 */
}

ユーザ処理(lcd_task.hとlcd_task.c)

cmsis_os.h、これは今は使わないけどいずれかならず使う

/*
 * lcd_task.h
 *
 *  Created on: Jan 13, 2026
 *      Author: usamiryuuichi
 */

#ifndef INC_PROC_LCD_TASK_H_
#define INC_PROC_LCD_TASK_H_

#ifdef __cplusplus
extern "C" {
#endif

void lcd_process(void);

#endif /* INC_PROC_LCD_TASK_H_ */


/*
 * lcd_task.c
 *
 *  Created on: Jan 13, 2026
 *      Author: usamiryuuichi
 */

#include "proc/lcd_task.h"
#include "st7789.h"
#include "cmsis_os.h"

void lcd_process(){
	ST7789_TestColors();
}

実際の動作は以下の動画、

全体の骨組みできてきたから、実際の処理に取り掛かれるかな

 

admin

STM32のADCの精度向上について

STM32F401REの実行精度は12bitsのADCでも10bits程度らしいのですが、条件によって精度が変わってくるのでちょっと比較をしてみた

<実行環境>

・STM32f401RE

・CubeIDE 1.19.0

・macOS Tahoe

 

<AGNDとGND>

普通に考えると、AGNDの方が品質良さそうに思うけれども、実はそれは思い違いで内部的には単にGNDと繋がっているらしく、それどころか通常のGNDよりもノイジーらしい

測定してみた結果

・測定条件

サンプリング周波数:200KHz

DMAバッファーサイズ:2,560 (512*5)

ADCのSampling Time : 56 Cycles

※ Sampling Timeの変更方法

① CubeMXのADC設定プルダウンメニューで選択

② buildでADC初期化処理に反映(赤で囲ったとこ)

ADCの入力をAGNDとGNDに切り替えて実測

計算方法

DMA転送された領域のlow側平均値を求めてるだけ、100以下判定はPWMじゃないときは不要

ということでAGNDの方がよりノイジーでした

 

<Sampling Time違いによる精度の違い>

ADCのサンプリング安定度:ADCの設定でSampling Timeが短すぎると結果が安定しない、なぜならADCサンプリンのCapの電荷蓄積ができない、あるいは外部ノイズの影響受けるから

従って、Sampling Time 最少3 Cyclesは安定性を考えると、可能な限り長く取った方が良い、200KHzサンプリング(5μSインターバル)ADC clock 21MHzだと56Cyclesの選択か

ノイズレベルの目安は1~1.5LSBとするとmax 2ぐらいが許容レベルかと思う、SPI動作は明らかにノイズ源になっているけれども、Sampling Time設定である程度は改善できていそう、実行の繰り返しで値は変わっているので数値は傾向を表しているだけと思った方が良い

Nucleoのボード(F401RE)上にC25の捺印はあるけど、部品は実装されていないけど、おそらくAGND関連じゃないかと思うのでそこにセラミックキャパシタ実装すれば振る舞いも変わってくるだろう、必ずしも改善じゃないかもしれないけども、STM32の12bits ADCの実行精度は10bitsと言われているのでそれほど高いレベルは望めない

 

admin

Debuggerでデフォルトはmain.cの最初の行で止まるを変更する¥

CubeIDEのデバッガーは、デフォルト設定ではmain.cの最初の行で止まるような設定になってるけど、いちいち止まんなくて良いよね、どう変更するの?

Run -> Debug ConfigulationsでSet break point at: のチェックを外せば良い、mainを変えればおそらく他のコードの先頭で止まるようになるんだろうね

単純だけど有用な設定だと思う

 

admin

 

STM32でST7789 LCD(240*320)をDMAで表示させる

LCD表示もDMA転送で表示させるようなライブラリがあるので、それ使ってデモプログラムを動かしてみた

https://github.com/AlexKaut/ST7789-STM32-DMA/tree/master/ST7789_STM32F103C8_Demo

<GPIOのピンの使い方>

実はCSは常時Lowにしてるから使ってないけど、

<CubeMXでのピン名称指定>

st7789.hでは以下のように定義されてるけど、最後の部分は落としてCubeMXで名称設定するのが正しいようです

<表示させてみた>

main.cにst7789関連のコードをデモプログラム参考に追加

はいこの状態では240*240設定なので、残りエリアはノイズが表示されます

<240*320対応の変更>

st7789.hファイルを変更します

<変更後の表示>

全面表示されるようになりました、LCDの種類によってはオフセット調整が必要な場合もあるらしい

<配線>

SPIのclock線(今SPI clockは21MHzに設定してます)はできるだけ短く、かつGND線とツイストしてインピーダンス下げた

実はDMA使うケースはそんなに多くないから、動作確認の比重が高いと思う、実際にはほぼプログラムモードでの制御になるから、データ準備でMCU介在するから

 

admin

STM32の周辺デバイスはCPU停止に関係なく動作継続

前回の記事、

STM32でのPWMの設定方法(コード/初期設定)

この記事に関連して、PWMの周波数が1/2**nだと綺麗にADCからの値取れるけど、任意の周波数入れると値がミックスしてグタグタ状態、なんでかなと色々調べると結局ADC変換のDMAがデバッガーで止めても動き続けるからどんどん同じ領域に上書きされるせい、たまたま1/2**nだと少なくとも位相はずれないから問題ないように見えるだけという結論

この検証のために、

① 正弦波入力してみたけどデータが綺麗に昇順降順にはならなかったから気づいた

10KΩ抵抗でGND – VCCを分割してcap(1.5μF)でカップリング、つまり電源電圧の中点をオフセット電圧にして、周波数5KHz、電圧は2V p-p(USBオシロの信号発生器を使う)、ADCのサンプリング周波数は100KHz

データレディのタイミングでDMA停止させて、ブレークポイントの先で再起動するように変更

概ね、20サンプルで1サイクルの値(単調増加と単調減少)が確認できた、数字的にも1.65 V ± 1Vぐらいの雰囲気

② PWMで5KHzを入力

こちらも概ね20サンプルで周回が確認できた、複数回停止しているので前回と値が変わったところは黄色になってる、上書きされると4095付近と0付近が混合されたメチャクチャな値になってた

<学び>

STM32のペリフェラルはCPUの状態関係なく動作するから、デバッグ時には考慮が必要

 

P.S. あとCubeMXの設定変更後に一度buildしてもdebuggerモード起動すると再度buildが必要になるのはMacのCubeIDEによくある問題らしい、二回buildすればいいだけではあるけども、debugger起動時にbuild結果の整合性チェックが通らないらしい

 

admin

STM32でのPWMの設定方法(コード/初期設定)

PWMでdutyを設定するときに、

__HAL_TIM_SET_COMPARE(&htim2, TIM_CHANNEL_1, 250);

のようなやり方と、

CubeMXの設定で設定は等価であると、

<環境>

・M4 MacBook ProでCubeIDE ver1.19.0

・STM32F401RE

・クロック系:ST-linkの水晶発振器を使ってFCLKは84MHz

 

<設定方法>

設定の場合にはPWM Generation *****のPulseでdutyを設定、この場合にはduty 50%になります

設定した結果の出力(84Mhz/(84*200) = 5KHz)、クロックソースが水晶なのでRC発信器と違って正確

この波形を、サンプリング周波数10KHzのADC(DMA転送)の入力に突っ込んでやると、

のように、High/Lowがサンプリングできています、同じクロックで同期しているので周期が狂うことはない

 

admin

 

CubeIDEでペリフェラルごとにソースコードファイルを分離

STM32で初期状態のままにペリフェラルを追加していくと、main.cの中にペリフェラル関連の初期化などの処理が全て組み込まれて、はっきり言って読みづらくなる

で、ペリフェラルごとにソースコード分離するのは実は簡単で、設定だけで対応できてプロジェクト開発の途中で変えても問題ない

 

.iocの設定、Project ManagerでCode Generator選択して、コード分離指定にチェックするだけ、この後プロジェクトを再度ビルドすると、

こんな感じにヘッダファイルとソースファイルがそれぞれ対応ディレクトリ以下に配置される、この方がはるかに普通だと思うよ

 

admin

ラズパイ5のデスクをUSB SSD(SATA)にしてみた

以前の記事でNVMeのSSDにした記事掲載しましたが、どうも安定して動作しないので結局SDカードに戻してましたが、今回USBのSATA SSDのケース買ってそこにイメージ写してシステムデスク(128GB SATA SSD)を変更してみた

<SDカードをUSB SSD化する>

SD Card Copierで丸ごとコピー(New Partition UUIDsにチェック忘れずに)

再起動で、

・boot orderの確認
pi@rasp5:~ $ sudo rpi-eeprom-config
[all]
BOOT_UART=1
POWER_OFF_ON_HALT=0
BOOT_ORDER=0xf146	#NVMe / USB / SDカードのオーダー
PCIE_PROBE=1

Sdカードよりも優先順位は高くなっているけど最優先にする

$ sudo rpi-eeprom-config --edit

で変更してrebootで、

$ sudo rpi-eeprom-config
[all]
BOOT_UART=1
POWER_OFF_ON_HALT=0
BOOT_ORDER=0xf164
PCIE_PROBE=1

SDカードは抜いてないから見えてるけど、USB SSDに切り替わった、loopxはsnapで仮想的にインストールされたモジュールが割り当てされるドライブネームなのでmountpointsは/snapから始まっている

ついでに性能測定、

     Category                  Test                      Result     
HDParm                    Disk Read                 361.17 MB/sec            
HDParm                    Cached Disk Read          327.60 MB/sec            
DD                        Disk Write                292 MB/s                 
FIO                       4k random read            29510 IOPS (118040 KB/s) 
FIO                       4k random write           24323 IOPS (97292 KB/s)  
IOZone                    4k read                   44614 KB/s               
IOZone                    4k write                  42302 KB/s               
IOZone                    4k random read            22563 KB/s               
IOZone                    4k random write           44361 KB/s               

                          Score: 12810         

sdカードに比較して書き込みは一桁上、MVNEe SSDのPCIe接続に比較すると1/3~1/4ぐらい、そんなものかな(以下のリンクは過去記事)

ラズパイ5のドライブをSSDにする

実装はこんな感じ、chatbotのエンビパイプの中に収めてる、

ケースは、

https://www.amazon.co.jp/dp/B0C2D1ZZGW?ref=ppx_yo2ov_dt_b_fed_asin_title

 

admin

Luantiサーバーのインストールとsnap

Wi-Fi内でローカルで使うためのLuantiサーバー、色々やってみたけど結局行き着いたのはラズパイ5

① wsl2:一見筋が良さそうだけど、Windowsのセキュリティを乗り越えられない、つまりportが通らない

② USB SSDでLinux:これだとWindows関係なくなるから筋は良さそうなのだけど、HP NoteBookのUEFIのガードが固くてUSB SSDのbootができない、bootableと認識していないということ

③ MacのVMware FusionのUbuntuで立ち上げる:これはMacBookのローカルからだと仲間と認識してもらえるけど、外部からは同様の問題がある、Fusion Proだと同じネットワーク内のアドレス取得されるから良さそうだけど、結局***.localは使えないよね

④ ラズパイ5:これがおそらく一番素直、つまり仮想マシン配下に構築すると必ずネットワークが通すための工夫が必要だけど、専用機なら何ら問題ないしmDNSも使えるから固定I Pである必要もない

<ラズパイ5でのインスト手順>

ここでsnapが出てくる、aptではLunatiが結構古いバージョンだったりするらしくて、最新版を取得するならばsnapを使う、ソースコンパイルという手段もあるけど結構手間ではある

$ sudo apt update
$ sudo apt install snapd

snapとはLinuxにおける新たなパッケージ管理ツール(アプリ単位の隔離で依存関係を全部まとめることでosから切り離されるからaptでインストールできないアプリもインストールできる)、サイズと起動時間がネックかなFlatpakがデスクトップアプリでsnapはサーバーサイドアプリという棲み分けかな、起動時間とか問題なること少ないし
https://www.choge-blog.com/programming/ubuntu-snap/

$ sudo reboot

snapdの最新版をsnapでインストールする
$ sudo snap install snapd

$ sudo snap install luanti

snapのラズパイ用のLuantiはクライアントとサーバーが兼用らしい

$ luantiで起動して作成ずみのworldをDLしてデフォルトに設定する

$ cat ~/snap/luanti/common/.minetest/minetest.conf 
server_announce = false
maintab_LAST = online
enable_damage = true
creative_mode = false
mainmenu_last_selected_world = 1
default_game = minetest 


$ mkdir -p ~/snap/luanti/common/.minetest/games/
$ cd ~/snap/luanti/common/.minetest/games/
$ git clone https://github.com/luanti-org/minetest_game.git minetest

起動
$ luanti --server --worldname test --gameid minetest --port 30000

2025-12-24 19:33:28: WARNING[Main]: system-wide share not found at "/usr/share/luanti"
2025-12-24 19:33:28: WARNING[Main]: system-wide share found at "/snap/luanti/11/usr/bin/../share/luanti"
2025-12-24 19:33:28: [Main]: Using world specified by --worldname on the command line
2025-12-24 19:33:28: [Main]: Using game specified by --gameid on the command line
 _                   _   _ 
| |_   _  __ _ _ __ | |_(_)
| | | | |/ _` | '_ \| __| |
| | |_| | (_| | | | | |_| |
|_|\__,_|\__,_|_| |_|\__|_|  ___ 5.14.0
2025-12-24 19:33:28: ACTION[Main]: World at [/home/pi/snap/luanti/common/.minetest/worlds/test]
2025-12-24 19:33:28: ACTION[Main]: Server for gameid="minetest" listening on [::]:30000.

クライアントの画面

snapは起動時間が長くなるというけど、サーバーなら起動しちまえば終わりだから問題にはならない、sdカード使ってるけど特にレスポンスが遅いとも感じない

あとサイズが大きくなる件は、これは媒体次第だけど今時それほどクリティカルな話ではない

 

admin

ラズパイのsdカードイメージのバックアップと復元

すぐにやり方忘れるので、過去記事に見当たらないので作成

<環境>

MacBook Pro M4/Tahoe

SDカード:ラズパイ5で使っている64GBのSDカード

 

<手順>

・Macに差し込んでdisk番号の確認

% diskutil list
/dev/disk0 (internal, physical):
   #:                       TYPE NAME                    SIZE       IDENTIFIER
   0:      GUID_partition_scheme                        *1.0 TB     disk0
   1:             Apple_APFS_ISC Container disk1         524.3 MB   disk0s1
   2:                 Apple_APFS Container disk3         994.7 GB   disk0s2
   3:        Apple_APFS_Recovery Container disk2         5.4 GB     disk0s3

/dev/disk3 (synthesized):
   #:                       TYPE NAME                    SIZE       IDENTIFIER
   0:      APFS Container Scheme -                      +994.7 GB   disk3
                                 Physical Store disk0s2
   1:                APFS Volume Macintosh HD            12.2 GB    disk3s1
   2:              APFS Snapshot com.apple.os.update-... 12.2 GB    disk3s1s1
   3:                APFS Volume Preboot                 8.1 GB     disk3s2
   4:                APFS Volume Recovery                1.2 GB     disk3s3
   5:                APFS Volume Data                    455.7 GB   disk3s5
   6:                APFS Volume VM                      5.4 GB     disk3s6

/dev/disk4 (disk image):
   #:                       TYPE NAME                    SIZE       IDENTIFIER
   0:      GUID_partition_scheme                        +17.3 GB    disk4
   1:                 Apple_APFS Container disk5         17.3 GB    disk4s1

/dev/disk5 (synthesized):
   #:                       TYPE NAME                    SIZE       IDENTIFIER
   0:      APFS Container Scheme -                      +17.3 GB    disk5
                                 Physical Store disk4s1
   1:                APFS Volume iOS 17.4 21E213 Simu... 16.8 GB    disk5s1

/dev/disk6 (external, physical):
   #:                       TYPE NAME                    SIZE       IDENTIFIER
   0:      GUID_partition_scheme                        *1.0 TB     disk6
   1:                 Apple_APFS Container disk7         1.0 TB     disk6s1

/dev/disk7 (synthesized):
   #:                       TYPE NAME                    SIZE       IDENTIFIER
   0:      APFS Container Scheme -                      +1.0 TB     disk7
                                 Physical Store disk6s1
   1:                APFS Volume Extreme SSD             370.5 GB   disk7s2

/dev/disk8 (disk image):
   #:                       TYPE NAME                    SIZE       IDENTIFIER
   0:      GUID_partition_scheme                        +17.6 GB    disk8
   1:                 Apple_APFS Container disk9         17.6 GB    disk8s1

/dev/disk9 (synthesized):
   #:                       TYPE NAME                    SIZE       IDENTIFIER
   0:      APFS Container Scheme -                      +17.6 GB    disk9
                                 Physical Store disk8s1
   1:                APFS Volume iOS 17.5 21F79 Simul... 17.0 GB    disk9s1

/dev/disk11 (internal, physical):
   #:                       TYPE NAME                    SIZE       IDENTIFIER
   0:     FDisk_partition_scheme                        *61.9 GB    disk11
   1:             Windows_FAT_32 bootfs                  536.9 MB   disk11s1
   2:                      Linux                         61.4 GB    disk11s2

最後の/dev/disk11が該当

・該当diskをunmountする

mountしたままではMacOSの配下にあって、キャッシュとかでまともにバックアップが取れないと

% diskutil unmountDisk /dev/disk11
でunmountする

・ddコマンドでバックアップイメージの作成

% sudo dd if=/dev/disk11 of=rasp5_chatbot.img bs=1m
でbackupが時間はかかる(おそらく30分近くかな)けど作成される

59024+0 records in
59024+0 records out
61891149824 bytes transferred in 1211.657719 secs (51079731 bytes/sec)

<復元>

復元時も同様にdisk番号取得してsdカードに書き込み(x)には取得したsdカードのdisk番号を入れる

% sudo dd if=rasp5_cahtbot.img of=/dev/disk(x) bs=1m

 

admin