Arduino は抽象度の高いライブラリとして優れていると思いますが、STM32 HAL ライブラリはクソだと思います。これは WMMC Advent Calendar 2020 19日目 の記事の二つ目です。
目次
WMMC Advent Calendar 2020 19日目 の記事の二つ目です。一つ目 の記事に技術寄りかつ役立ちそうなことが書いてあります。この記事は深夜テンションで書き上げた文章なので面白みに欠けると思います。残念でした。
【注意】この記事の大部分の内容は、個人の主観に依る所が大きく、一般性・客観性に欠いています。また、事実と全く異なる記述や過激な表現が随所に含まれますが、誹謗中傷の意図は無く、エンターテインメントの一貫としてお楽しみください。
大阪の天王寺・阿倍野は、難波、梅田に次ぐ大阪第3の繁華街として栄えています。天王寺公園・動物園といった観光名所を携える一方で、目と鼻の先には関西随一の料亭街である飛田新地が鎮座するという、大阪のカオスが感じられるステキなマチであります。天王寺・阿倍野は交通の要衝でもあり、天王寺駅は大阪環状線から阪和線・関西本線が分岐し、かつては南海電車も乗り入れていた大ターミナル駅です。近鉄も忘れてはなりません。天王寺駅に隣接する大阪阿倍野橋駅は近鉄南大阪線の終点であります。隣接する駅が違う名を名乗る光景は、かつての業平橋駅・押上駅と似たものを感じます。

さて、この近鉄大阪阿倍野橋駅には、これに接続する形で日本一の高さを誇る超高層ビルディング「阿倍野 HAL カス」がそびえ立っております。この「阿倍野 HAL カス」という奇妙な名前、その由来は紛れもなくあの忌わしき STM32 HAL ライブラリ ではありませんか! きっと、HAL ライブラリによって多大なる苦労を強いられた近鉄の組み込み系エンジニアが「HAL……お前だけは絶対に許さない……」という堅い意思でもって名付けられたのでしょう。「阿倍野 HAL カス」は HAL に SAN値を削られた近鉄社員が日本国民に向けて発出した最後のメッセージであり、墓標とも言えるでしょう。

見て下さいこのキャラクターの反抗的な目付き。「ST社、絶対、○す」とでも言わんばかりの野獣の眼光のようなものすら感じられます。
HAL ライブラリの何がクソなのか?
私は STM32 マイコンを使っているのですが、そのマイコンの自称高レイヤライブラリが何か使いづらくてイライラしているのです。その名も STM32 HAL ライブラリと言います。
某先輩をはじめとして、HAL ライブラリに嫌悪感を抱く人間は一定数居るようです。皆さん、この記事を読んで、HAL ライブラリに対する態度を改めてください。
それでは始めます。
HALライブラリよぉ。お前さぁ。いい加減にしろよ。お前の何がクソかて? まずマニュアルがクソだよな。これに尽きる気がする。お前これ人にちゃんと説明する気あるのかよオイ。
HALライブラリにはマニュアルが存在します。↓はF3シリーズのHALライブラリのマニュアルです。
これを見たあなたは驚くでしょう。なんという図の少なさ! 説明がとにかく簡素で読みやすい!シンプル! is! ベスト!
……まぁ要は何が言いたいのかと言うと、HALのマニュアルなのでHALライブラリの使い方しか書いてないわけでして、各ペリフェラルの仕様や挙動についてはほとんど記されていないわけです。すなわち、リファレンスマニュアルを併用する必要があるわけです。なんてこった! I/Oレジスタ地獄から解放されたと思ったのに結局リファレンスマニュアル読むのか!
まぁ、リファレンスマニュアルが必要ってだけならこんなにキレ散らかしていませんが、問題は HAL のマニュアル読んでも HAL の使い方すらよく分からないって所にあると思います。は? ふざけんなよ?
過去の経験談をお話します。SPI の送信を割り込みモード?で動かそうと思ったことが昔ありました。HALライブラリを使えば楽に実装できるだろうと信じて止まなかった私は、HALのマニュアルをダウンロードしてSPIの箇所を読みました。ふむふむ。HAL の SPI 送信関数には HAL_SPI_Transmit と HAL_SPI_Transmit_IT と HAL_SPI_Transmit_DMA があるのだな。とまあ、それぞれの関数が意味しているものはなんとなく分かるのですが、私の読解力が低いのも相まってか、使い方がよくわからないのです。割り込みモード?で送信する場合は HAL_SPI_Transmit_IT を使うべきって所まではわかるのですが、マニュアルには、その関数の説明が「Transmit an amount of data in non-blocking mode with Interrupt」とだけ記載されていました。ふーむ。まぁ送信完了割り込みが起こるたびに送信レジスタに1バイトずつデータをブチ込むような実装にすれば、たしかにメインルーチンを non-blocking で複数バイトの送信は可能か。そういう実装をすれば良いのか。賢いな。流石HALライブラリ。いや待てよ、お前はどこまで実装してくれてるんだ? 送受信割り込みハンドラ内の処理も実装してくれているのか? それともそこは自分で実装せなアカンのか???
……このように、HALライブラリはどこまでカバーしてくれているのか、どこは自分たちで実装しないといけないのか、マニュアル見ただけでは不明瞭ということがしばしばある気がします。
このような状況に陥った時、やるべきことは次に示す2つのどちらかです。
- サンプルプログラムを探す
- HALライブラリのソースコードを解読する
簡単なのは、他人が書いたサンプルプログラムをコピペすることです。コピペは悪いことではないと思います。むしろ、ライブラリってのは、サンプルプログラムを充実させてコピペするだけで簡単に実装できちゃう。スゴイでしょ!が理想型な気がします。で、私はサンプルプログラムを探すわけですけど、なかなか見つからないのです。探し方が良くなかったのか、はたまたやろうとしていたことがマニアック過ぎて先駆者が居なかったのか。これは困った……。
となると、できることはただ一つ! HALライブラリの †卍ソースコードの解読卍† です。ソースコードさえ解読してしまえば、HALライブラリを完全に理解することが可能です!!!すごい!!!!! ……ってな感じで、私はソースコードを解読することによって所望のプログラムを書くことに成功したわけですが、HALライブラリを使うことが、果たしてホントに楽できる最善策なのか、甚だ疑問に感じるようになりました。
ここまで、私自身の体験談を語ってきましたが、これだけでは説得力に欠いてしまう気がします。しかし先日、私に考えの近い ST Community の投稿を発見しましたので紹介します。
▶ https://community.st.com/s/question/0D50X00009sW5Ld/halspitransmitit-blocks
この投稿は、「HAL_SPI_Transmit_IT で Single Byte 送信する時の挙動が理解できない」といった内容の質問から始まるのですが、この質問に対する最初の返信が「Look at the HAL SPI source code, ……」で始まっています。HALライブラリの挙動が分からないなぁ……よおし、ソースコードを読もう! この解決法は万国共通なようです。
この投稿には他にも秀逸な返信があります。
「By using a “library” you decided to live with whatever design decisions the “library” authors chose.」「Are you dissatisfied with other’s code? Feel free to write your own.」
“ライブラリ”を使うってことは、その作成者が決めたルールに従順になるってことなんだよ。嫌なら自分で作れ。
なんて素晴らしいお言葉なのでしょう。家訓にしたいフレーズです。
この言葉を聞いて、HAL ライブラリとはおさらばして、自分でもっとマシなライブラリを作ろうと決めました。……とはならず、HALをディスるのを辞めて、諦めてHALのルールに従いHALと付き合っていく道を私は選ぼうと思います。
……まぁでもさっきから私が指摘しているHALの問題点って、HALの設計とかルールがクソって話ではなくて、ソースコードを読まない限りHALのルールが分からないって所なんだよな。やっぱHALはクソだな。
Hardware Abstraction Layer ライブラリ、略して HAL ライブラリなわけですが、中途半端な抽象度なんですね。そりゃ、I/Oレジスタを生で操作するよりは抽象的なんでしょうけど、mbed や Arduino のような抽象度では全然ないわけで、低レイヤの知識、要はリファレンスマニュアルに書いてあるようなことは知る必要があるのです。加えて、HALの挙動を知るためのにソースコードを読む必要があるとなれば、それってもう結局 I/Oレジスタ叩いてプログラム書いてるのとほとんど同じでは? と私は強く思うわけです。
Abstraction Layer とか名乗っておきながら、かなり Low Layer なライブラリ、それが STM32 HAL であります。HAL をもっと使いこなしたいと考えているあなた、少し遠回りだけど、I/Oレジスタ叩いてプログラムを書いてみる経験をしてからのほうが、案外スムーズかも知れないゾ。
私の考えるHAL ライブラリの使い方
使い方が分からなければソースコードを読む
ソースコードさえ読めば全てが分かります。
Cube IDE など、Eclipse 系の開発環境では、関数名や変数などを選択して『F3』キーを押せばその定義や宣言が書かれた箇所に簡単にジャンプすることができます。

また、『Ctrl + H』キーで表示される検索画面では、プロジェクト全体を対象に検索をかけることができます。

こういった機能を駆使しまくって、ソースコードを効率よく解読しましょう。
一度使い方が分かればとても便利
別に私は HAL ライブラリが無価値で今すぐにでも絶滅すべき存在であると言いたいのではありません。一度使い方が分かってしまえば、たった数行書くだけで複雑な処理を済ませられる、素晴らしいライブラリに化けます。
最近 STM32 を使う時は必ず HALライブラリを使っています。ありがとう。HAL。
HALのソースコードはI/Oレジスタを操作する上で手本になる
HALライブラリは公式ライブラリゆえ、その動作は恐らく保証されています。ゆえに、ソースコードの手順通りにI/Oレジスタを操作すれば確実にSTM32を動かすことが可能なのです。I/Oレジスタ操作の Example プログラムとしての HALライブラリは大変有能です。
編集後記
なんだこのしょーもない記事は……。
この歳になるとクリスマスを意識することすらしなくなります。強く生きましょう。