NucleoのHALのプログラムについて（素人目線で）いろいろ考えるだけ

#この記事は？？？
鈴鹿高専アドベントカレンダーの8日目の記事です。

https://qiita.com/advent-calendar/2021/snct

#HALってなんですか？？？？？？
Nucleoを使っていく上でHALを使ったプログラムについて、素人目線でちょこっと書いておこうと思います。

と言っても、筆者はプログラム歴が浅いのと、Qiitaに記事を投稿するのは初めてなので、間違っているところなどありましたらコメントで教えてください。

今現在、筆者はNucleoのマイコンをちょこちょこ使い始めていますが、もともとはmbedやarduinoなどのマイコンを使ってきました。今回新しく使い始めたNucleoでの技術を備忘録としても残しておきたいなと思って書いています。
また、STMCubeIDEの記事も少なめだったので、それについても少し書いてみます。

環境
---
・Windows11 Pro (64bit)
・nucleo (STM32 Nucleo-F767ZI)
・STM32CubeIDE　(ver1.7.0)

#HALとは...?
HAL(Hardware Abstraction Layer)とはハードウェア抽象レイヤのことで、ハードウェア、ソフトウェア間に存在するレイヤです。ハードウェアごとの差異を無くすために作られたもので、ソフトウェアの最下層に作られているものだそうです。割と一般的な技術のようで、様々なところ(主にコンピュータ関連)で使われています。

NucleoでもHALが使えるようになっています。レジスタに値を直叩きしなくとも書けます、ということです。マイコンでこれが使える事のメリットは、移植作業が簡単であるということなんですねー。よってSTM32ファミリーもといSTM8ファミリーでは、ハードウェアについて考えずとも、HALのプログラムを書けば動くらしいです。

[HAL（ハードウェア抽象化レイヤー）って何？](https://ednjapan.com/edn/spv/2108/31/news034.html)

#HAL基本関数
ここからはNucleoのプログラムを書く上で使うことのあるかもしれないHALの話に入っていきます。ぶっちゃけmbed開発環境使えば楽ですが、いろんな理由で使う時は出て来るかなと...

ちなみに公式のリファレンスは広告が凄いです、まじで。

[STM32F439xx HAL User Manual](http://www.disca.upv.es/aperles/arm_cortex_m3/llibre/st/STM32F439xx_User_Manual/group__uart__exported__functions__group2.html)

こちらは英語の記事ですが、リファレンスとしてしっかりまとまっています。

[ファームウェア関数一覧](https://www.minokasago.org/STM32wiki/?%E3%83%95%E3%82%A1%E3%83%BC%E3%83%A0%E3%82%A6%E3%82%A7%E3%82%A2%E9%96%A2%E6%95%B0%E4%B8%80%E8%A6%A7)

上の記事は日本語で、こちらもしっかりまとめられてあるのでオススメです

またNucleoの公式のHAL and lowlayerのユーザーマニュアルがあります。怒涛の2000ページです。文庫本約8冊程度(?)なので、シリーズ物を読むつもりで目を通してみてはいかがでしょうか？

[Description of STM32F4 HAL and low-layer drivers](https://www.st.com/resource/en/user_manual/dm00105879-description-of-stm32f4-hal-and-ll-drivers-stmicroelectronics.pdf)



##(ちなみに)HALについての賛否両論
HALというのは抽象度が高いので、「レジスタ直叩きじゃねえのは漢じゃねえ！」という方も多々おられます。

でも、ちゃきちゃきの生粋のarduinoライブラリユーザーからしたら、HALといえどもそこまで抽象度が高い感じはしないです。抽象度か高いからと言って、可読性もそこまで高いわけではないですからね。

今まで~~楽ちんな~~抽象度の高いプログラムを書いてきたが故のことかもしれないですね:eyes:


何にしろ、内部構造を理解するのは大事ではあるので、抽象化レイヤを使いつつ、レジスタ直叩きの経験はあったほうがいいと思いました(小並感)

#STM32CubeIDEを使って、HALのプログラムを書いてみよう！
早速書いてみます。今回は、STマイクロから出てるIDE「STM32CubeIDE」を使っていこうかなと思います。STM32CubeMXの自動コード生成機能が付いてます。

まずは開いてみましょうかね～

![スクリーンショット (112).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1500513/7f2c9a5d-84a1-9b2c-366a-8ffb8330680e.png)

ぬお～！出てきました。まあとりあえず書いていきます。

![スクリーンショット (121).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1500513/0512a38c-1cb7-c6e2-38ad-3ae488e21a35.png)

これがCubeMXで使えたコード自動生成機能です。CubeIDEでも同じように、コードは自動生成のやつを使っていきます。
ここら辺の使い方を書いた記事は、良記事が他にございますので、そちらを参考にしていただいた方がいいと思います。

[STM32入門 環境構築「CubeIDEのインストールとSTM32F446でLチカ」](https://qiita.com/yosihisa/items/136bcc09c466227303a2)

上の記事は、私がCubeIDEを使う時に大変参考になった記事です。


さあ、今回の本題に入っていきましょう！CubeIDEでは

```
/*USER CODE BEGIN ○○*/
~
/*USER CODE END ○○*/
```
の間にユーザーのプログラムを書きます。それ以外のところに書くとコードが消え去ったりします。（悲しい）そんな悲しいことにならないように、ちゃんと確認して書きましょう。

**今回のサンプルプログラムは「エンコーダー」です。**

ペリフェラル設定はこんな感じ。追加のペリフェラル設定しなかった覚えがあるんですが、どうなんでしょうかね...うろ覚えなんですよね...
参考にした記事を貼っておきますので、こちらを見ながらの方がいいかもしれないです

[【Nucleo入門】Nucleo-F401でエンコーダ読み取り（STM32CubeIDE、macOS版）](https://www.shujima.work/entry/2019/05/28/221629)
![スクリーンショット (158).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1500513/56e94918-8ff9-ddf6-5e19-d1a1fec51adf.png)

includeをしていきます

```
#include <stdio.h>
#include <string.h>
#include <stdint.h>　//今回のプログラムに必要ない
```
自分は心配性なので、使わなくてもincludeしてしまいます。まあ、そこらへんで問題は今だ出てないので、いいかなーと思います（適当ですいません）

肝心のコードを書きます

```
/* Initialize all configured peripherals */
  MX_GPIO_Init();
  MX_USART3_UART_Init();
  MX_USB_OTG_FS_PCD_Init();
  MX_TIM3_Init();
  MX_USART2_UART_Init();
  /* USER CODE BEGIN 2 */
  HAL_TIM_Encoder_Start(&htim3, TIM_CHANNEL_ALL);
  int cnt;
  char scnt[100];

  /* USER CODE END 2 */

  /* Infinite loop */
  /* USER CODE BEGIN WHILE */
  while (1)
  {
	  cnt = TIM3 -> CNT;
	  sprintf(scnt, "%d\r\n" , cnt);
	  HAL_UART_Transmit(&huart3, scnt, strlen(scnt) + 1, 0xffff);
	  HAL_Delay( 100 );
    /* USER CODE END WHILE */

    /* USER CODE BEGIN 3 */
  }
  /* USER CODE END 3 */
}
```
このようにすると、Teratermのシリアル通信で値が見れます。
今回のプログラムで使われたHAL関数はこちらです

```
・HAL_TIM_Encoder_Start(&htim3, TIM_CHANNEL_ALL);
・HAL_UART_Transmit(&huart3, scnt, strlen(scnt) + 1, 0xffff);
・HAL_Delay( 100 );
```
一個目から「エンコーダインフェースを有効化し読み取りをスタートさせる関数」、「UARTでデータを送る関数」、「遅延を挿入する関数」です。

これがnucleoでHALを使ったプログラムです。~~別に変わったことはないですね~~ これであなたも私も「HALﾌﾟﾛ(?)」になったわけです。おめでとうございます。
#HALやNucleoでプログラムを書くのに感じたこと
ここからはポエムで、今回の題名の答えです。

まずは気になる点から

まず、Nucleoのプログラムを書くのに、基本HAL関数は使うこともあるのに、基本関数一覧やリファレンスを検索しにくい気がします。例えば自分なら、「nucleo プログラム」くらいでも上位にヒットして欲しいくらいです。

ていうかHALの存在自体何や？？？？？って感じでした。

~~mbed開発環境の方が楽だけど~~　なんやかんやで使うと思いますしねHALは

mbed開発環境とか使うよりかハードウェアにより近いのかな...それはよくわからん

あと、HALが抽象的だからといって、可読性が高いという訳でもない気がします(上の方でも書きましたが)

コード自動生成の機能を基本的に使っていく前提でプログラム書いた方がいいのかなとも思いました。

あと、日本語の使い方ガイド的なのあったら嬉しい。ﾜﾀｼｴｲｺﾞﾀﾞﾒ

次に良かった点
HALとはあまり関係無いかもしれないですが、CubeMXのコード自動生成は楽だと思いました。ていうかないとあの量のプログラム書きたくない

Nucleo自体、ペリフェラルをたくさんつなげられて楽しいので、色々掘り下げていきたいなと思います。

HALについては、レジスタ叩くということが必要ないのがいいのかも。

##（ちなみに）nucleoでレジスタたたいてプログラムを書くとどんな感じか

[STM32のレジスタを叩く　#1 ~GPIO編~](https://rappy.hatenablog.com/entry/2019/11/17/221651)

こちらの記事が参考になると思います。

#HALマスターに俺はなる！！！！