STM32 LLでUARTしてみる 送信(ポーリング編)

STM32 LLでUARTしてみる 送信(ポーリング編)

皆さま こんにちは。

今回は LL を使ったUARTによる通信の送信をポーリングで行ってみます。

LLってな~に?という方は HALとLL の記事をご覧ください。

投稿時の開発環境を記しておきます。

PC:Windows10 OS
IDE: STM32CubeIDE Version1.5.0
Configurator: STM32CubeMX Version6.1.0
Board: STM32Nucleo-F401RE

ポーリングによる送信

送信にポーリングという表現が適切かどうかわかりませんが、連続してデータを送る際に次のデータを送ってよいか確認しながら送る方法です。

この先LLを使っていくにはペリフェラルのレジスタについて理解しておく必要があります。

そのために、このボードで使っているマイコンのリファレンスマニュアル RM0368 を こちら からダウンロードしておいてください。

今回は UART を動かしますので 19項の USART の部分を良くご覧になってください。

USARTのSは Synchronous : 同期の意味で、USARTは同期、非同期のシリアル通信を行うことができるペリフェラルです。
UARTはUSARTに含まれている と考えておけば良いでしょう。

LLでUARTを使うためのIDEの設定は STM32 LLでUARTしてみる 初期設定編 の記事を参照してください。

USARTのレジスタ解説

ひとまず制御レジスタ1(CR1)と2(CR2)の部分を良く読んでみてください。

まず制御レジスタ1について見てみます。

私が理解している範囲で説明していきます。

ビット15 : オーバーサンプリングモード

0を設定し、16倍のサンプリングで良いでしょう。
詳しい説明は省きますが、クロックのない非同期通信なので、受信側がスタートビットを検出してからサンプリングを開始するビット幅あたりのクロックの数です。
この数の半分あたり(各ビットの中央付近)のクロックでデータをサンプリングします。

ビット13 : USART有効

USARTを使うために1を設定しなければなりません。
初期設定が終わった段階で、もしこのビットが0なら1を立てるコードを追加しましょう。

ビット12 : M ワード長

今回はデータ7ビット+パリティなので、この設定は 0

ビット11 : ウェイクアップ方法

使わないのでデフォルト(リセット時)のまま 0

ビット10 : PCE パリティ制御有効

おそらく Parity Check Enabled の略。
今回はパリティを使うので 1

ビット9 : PS パリティ選択

おそらく Parity Select の略。
偶数パリティなので 0

ビット8 : PEIE パリティエラーの割り込み有効

おそらく Parity Error Interrupt Enabled の略。
使う必要はないと考えているので 0

ビット7 : TXEIE 送信エンプティ割り込み有効

おそらく Tx Empty Interrupt Enabled の略。
今すぐは使わないので、とりあえず 0
割り込みを使った送信を行う場合に 1 にします。

ビット6 : TCIE 転送完了割り込み有効

おそらく Transmit Complete Interrupt Enabled の略。
使わないので 0

ビット5 : RXNEIE

おそらく Rx Not Empty Interrupt Enabled の略。
今すぐは使わないので、とりあえず 0

ビット4 : IDLEIE IDLE割り込み有効

使わないので0

ビット3 : TE トランスミッタ有効

おそらく Transmitter Enabled の略。
送信するので、もちろん 1

ビット2 : RE レシーバー有効

後で使うので 1

ビット1 : RWU レシーバーウェイクアップ

使わないので 0

ビット0 : SBK ブレーク送信

使わないので 0

次に制御レジスタ2

制御レジスタ2では、今回理解しておくのはストップビットの部分です。
ビット12,13がストップビットを設定する部分になりますが、今回ストップビットは1なので、それぞれに0を設定すれば良いことになります。

ただしコンフィグレーターが初期化コードをつくってくれているので、設定は不要です。

それ以外のビットは、おそらく同期式で使う機能だと思います。
UART(非同期式)では使わないので、各ビットは初期値 0 で良いです。

まとめると、初期設定が終わったところで

制御レジスタ1(CR1)は 0x240c
制御レジスタ2(CR2)は 0x0000
(今は使わないので)制御レジスタ3も 0x0000

であることを確認しておけば良いですね。
デバッグ時に確認しましょう。

LL と ベアメタル

HALやMbedを使わないでレジスタに直接アクセスする方法をベアメタル(むき出しの金属 の意味)と言うようです。

私的には、ベアメタルより LL を使うことをお奨めしたいです。

理由としては、LLはインライン関数が多いのでベアメタルとの速度差はほとんどないと考えて良く、その上関数形式の英語になっているので、ベアメタルに比べて何をしているのかわかりやすいからです。

例えば後からソースコードを見た時に、わかりやすければメンテナンス性も良いはずですね。

NucleoボードのUSART2と仮想COMポート

main()関数の中に MX_USART2_UART_Init() という関数があります。

デフォルトモードで初期化したことによって、この関数が生成されています。

初期化によって PA2 が USART2 の TX (送信)に、 PA3 が USART2 の RX (受信)に割り当てられています。

回路図を見ると、これらの端子はデバッガ用のマイコンとつながっていることがわかります。

USBケーブルでNucleoボードとパソコンを接続すると、パソコン側で仮想COMポートとして認識されるようになっています。

そしてそのままでシリアル通信できる環境ができあがっているのです。

一般的には

マイコン – RS232CのドライバIC <---RS232Cクロスケーブル---> RS232CのドライバIC – マイコン

のような接続になるのですが、STマイクロのボードを使うとUSBケーブルでつなぐだけですむのでシリアル通信のテストを行うのに便利です。

ボードを選んでデフォルトモードで周辺機能を初期化した状態で、USARTの機能を使える準備ができているわけです。

パソコン側の準備を行う

パソコン側もデータを送受信できるアプリを準備しなければなりません。
ここでは Tera Term を使います。(お持ちでないかたはネットで検索してダウンロードしてください)

Tera Termを起動してシリアル(E)を選択し、ポート(R):で STLink Virtual Com Port が含まれているCOMポートを選択しOKボタンを押します。
こちらの環境では COM5 が Virtual Com Port に割り当てられていました。
STのシステムが仮想的にCOMポートの環境をつくってくれているので使わせて頂きましょう。

次に メニューの 設定 – シリアルポート から通信パラメータを以下のように設定しOKボタンを押します。

(注)前回の記事でお話した通り、パリティを使うためにマイコン側のデータ長は8、パソコン側は7に設定します。

もうひとつ 設定 – 端末 画面でローカルエコーにチェックを入れておきます。
これでキーを押すと、その文字を送り画面に表示します。

マイコンボードとパソコンをUSBケーブルで接続しておいてください。

コーディングする

main.cを以下のようにコーディングします。

/* USER CODE BEGIN WHILE */
while (1)
{
  TransmitData();
  HAL_Delay(3000);
  /* USER CODE END WHILE */

  /* USER CODE BEGIN 3 */
}
/* USER CODE END 3 */
void TransmitData(void);

#define _CR 0x0d

void TransmitData(void)
{
  uint8_t buffer[] = {
    '#', 'a', 'b', 'c', 'd', 'e', _CR
  };

  for (int i = 0; i < sizeof(buffer); i++)
  {
    LL_USART_TransmitData9(USART2, (uint16_t)buffer[i]);
    while (!LL_USART_IsActiveFlag_TXE(USART2))
    {
      ;
    }
  }
}

コーディングが終わったらビルドしてエラーがないことを確認しておいてください。

プログラム概要

パリティを含む場合、
データを1バイト送信するには LL_USART_TransmitData9() を使います。
( パリティなしの場合にはLL_USART_TransmitData8() )
この関数はUSARTのDRにデータをセットすることで送信を開始します。

データを立て続けに送ることはできないので、送る準備ができたらデータをセットします。
while (!LL_USART_IsActiveFlag_TXE(USART2)) の部分ですね。

TXEは、おそらく Tx DR Empty の略で、関数はDRが空っぽになったら1を返します。
空っぽでない間に待つために ! をつけています。

buffer 最後の _CR (0x0d) は 改行コードの CR です。
Tera Term側では、これを受けて改行してくれます。

動かしてみる

まず main.c の while(1) の行の行番号をダブルクリックしてブレークポイントを貼り、プログラムを実行します。

ブレークポイントで停止した時点ではUSARTの設定は終わっています。

Window - Show View - SFRs を選択します。

SFRsはスペシャルファンクションレジスタで、ペリフェラル用レジスタの略です。

> USART2 の > をクリックして V にして展開することでレジスタの値を確認することができます。

CR1 : 0x240c
CR2 : 0x0
CR3 : 0x0

となっていて思惑通りの設定になっています。

それではプログラムを実行してみましょう。

Run - Resume を選択します。

PCのTera Termで3秒毎に文字列 #abcde が表示されれば成功です。

パリティを変更してみる

Tera Termの設定でパリティを8bitにかえてみてください。

文字化けしてしまうことが確認できました。仕様上のデータ7ビットによる送信が行われているということでしょう。

ポーリング送信について

ポーリング送信のプログラムは簡単ですが、送り始めから終わりまでの間プログラムを占有してしまうというデメリットがあります。

次回は効率がよい割り込みを使った送信についてみていきます。

今回はこのへんで、お疲れさまでした。

関連記事

STM32 LLでUARTしてみる 送信(割り込み編)
STM32 LLでUARTしてみる 送信(DMA編)

LLカテゴリの最新記事