記事の概要
STM32マイコンのUART機能をHALライブラリを用いて使用する方法を解説します。
一般的にはSTM32CubeMXコード生成ツールを使うことが多いと思いますが、ここでは直接HALライブラリから関数を呼び出して設定を行います。
また、通常のモードについてのみ解説し、DMA機能については解説していません。
USART
STM32ではUART機能をUSARTとも呼んでいます。
正確にはUSARTは非同期なUART通信、SPIマスター通信、LIN(ローカル内部ネットワーク)などの複数のシリアル通信機能を兼ね備えたモジュールです。
例えばSTM32F407には4つのUSARTモジュールと2つのUARTモジュールがあります。
UARTモジュールにはSPIマスター機能に対応していないことが分かります。
サンプルコード
例えばUSART3モジュールを使用する場合、以下のように設定します。
UART受信は割り込み処理しています。
# include "stm32f4xx.h"
# include "stm32f4_discovery.h"
uint8_t byte;
UART_HandleTypeDef huart3;
void USART3_IRQHandler(void)
{
HAL_UART_IRQHandler(&huart3);
}
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
if (huart->Instance == USART3)
{
HAL_UART_Transmit(&huart3, &byte, 1, 100);
HAL_UART_Receive_IT(&huart3, &byte, 1);
}
}
void uart_init(void)
{
__HAL_RCC_GPIOD_CLK_ENABLE();
__HAL_RCC_USART3_CLK_ENABLE();
GPIO_InitTypeDef GPIO_InitStruct;
GPIO_InitStruct.Pin = GPIO_PIN_8 | GPIO_PIN_9;
GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
GPIO_InitStruct.Pull = GPIO_PULLUP;
GPIO_InitStruct.Speed = GPIO_SPEED_LOW;
GPIO_InitStruct.Alternate = GPIO_AF7_USART3;
HAL_GPIO_Init(GPIOD, &GPIO_InitStruct);
huart3.Instance = USART3;
huart3.Init.BaudRate = 115200;
huart3.Init.WordLength = UART_WORDLENGTH_8B;
huart3.Init.StopBits = UART_STOPBITS_1;
huart3.Init.Parity = UART_PARITY_NONE;
huart3.Init.Mode = UART_MODE_TX_RX;
huart3.Init.HwFlowCtl = UART_HWCONTROL_NONE;
huart3.Init.OverSampling = UART_OVERSAMPLING_16;
HAL_UART_Init(&huart3);
HAL_NVIC_SetPriority(USART3_IRQn, 1, 0);
HAL_NVIC_EnableIRQ(USART3_IRQn);
HAL_UART_Receive_IT(&huart3, &byte, 1);
}
ポート端子設定
UART機能に使用するポート端子の設定を行います。
USART3の場合は、TX端子はPD8、RX端子はPD9です。
マイコンのモジュールは、初期状態では消費電力を抑えるために停止しています。
GPIODにクロック供給することで起動してやります。
__HAL_RCC_GPIOD_CLK_ENABLE();
GPIO_InitStructの設定を行います。
ポート8番と9番を指定します。
GPIO_InitStruct.Pin = GPIO_PIN_8 | GPIO_PIN_9;
プルアップ設定にしているのは、初期からポート出力をにしておき、ハイインピーダンス状態による不安定さを回避するためと私は解釈しています。
GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
GPIO_InitStruct.Pull = GPIO_PULLUP;
速度は低速にしていますが、高速にしても特に動作に支障はありませんでした。
GPIO_InitStruct.Speed = GPIO_SPEED_LOW;
1つの端子は複数の機能に使い分けることができます。
マイコン内部に選択回路があり、AFレジスタを設定することで、ポート端子と様々なモジュールとの接続を切り替えています。
その選択をするのがAlternate
です。
マニュアルのPD8とPD9を見ると、UART機能を選択する設定はAF7です。
(もしPD8とPD9をFSMCのD13とD14として使用したい場合はAF12に設定します。)
GPIO_InitStruct.Alternate = GPIO_AF7_USART3;
UART通信設定
UARTの実体UART_HandleTypeDef
を作成しておきます。
UART_HandleTypeDef huart3;
GPIODと同様にUSART3モジュールにクロックを供給します。
__HAL_RCC_USART3_CLK_ENABLE();
通信速度、データ長、ストップビット、パリティビットを設定します。
ここでは通信速度を115200bps、データ長8bit、ストップビット1bit、パリティビットなしに設定しています。
huart3.Instance = USART3;
huart3.Init.BaudRate = 115200;
huart3.Init.WordLength = UART_WORDLENGTH_8B;
huart3.Init.StopBits = UART_STOPBITS_1;
huart3.Init.Parity = UART_PARITY_NONE;
モードはRXモード、TXモード、TX_RXモードがあります。
送受信の機能を使用するのでTX_RXモードにします。
huart3.Init.Mode = UART_MODE_TX_RX;
ハードウェアコントロール(RTS端子とCTS端子)を使用するかを選択します。
ハードウェアコントロールを使用しないので、設定をUART_HWCONTROL_NONE
にします。
huart3.Init.HwFlowCtl = UART_HWCONTROL_NONE;
オーバーサンプリングは8倍と16倍があります。
クロックずれによる最大受信耐性を増加させたいので、16倍を設定します。
huart3.Init.OverSampling = UART_OVERSAMPLING_16;
以上の設定を有効化します。
HAL_UART_Init(&huart3);
UART送信
以下の送信関数によりデータ送信できます。
uint8_t data;
byte = 'A';
HAL_UART_Transmit(&huart3, &data, 1, 100);
第1引数にはUSARTモジュールの実体であるUART_HandleTypeDef
を代入します。
第2引数には送信データの先頭アドレスを代入し、第3引数には送信データサイズを代入します。
第4引数はタイムアウトの時間です。この時間を過ぎても通信できない場合、エラー終了します。
例えば、10文字のデータを送信したい場合は以下のようにします。
HAL_UART_Transmit(&huart3, (uint8_t *)"FreeRTOS\r\n", 10, 100);
UART受信
データをUART受信すると割り込み処理が発生するように設定します。
HAL_NVIC_SetPriority(USART3_IRQn, 1, 0);
HAL_NVIC_EnableIRQ(USART3_IRQn);
受信待機処理HAL_UART_Receive_IT
を実行して、データ受信できるようにします。
ここではUART通信開始時に、1バイトデータを受信待機するように命令しておきます。
HAL_UART_Receive_IT
を実行しないと、データ受信できないのでご注意ください。
HAL_UART_Receive_IT(&huart3, &byte, 1);
UART受信により以下のハンドラーが呼び出されます。
void USART3_IRQHandler(void)
{
HAL_UART_IRQHandler(&huart3);
}
ハンドラーからコールバック関数HAL_UART_RxCpltCallback
が呼び出されます。
コールバック関数内で、USART3の実体Instance
であるかの確認をします。
そして、ユーザーのしたい処理を行います。
ここでは受信したデータをそのまま送信し返してから、再度1バイト受信待機処理を実行して、次のデータに備えます。
1バイト受信したことで最初に設定したHAL_UART_Receive_IT
は無効になっているので、再度HAL_UART_Receive_IT
を実行しないとデータ受信できなくなっているのでご注意ください。
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
if (huart->Instance == USART3)
{
HAL_UART_Transmit(&huart3, &byte, 1, 100);
HAL_UART_Receive_IT(&huart3, &byte, 1);
}
}
参考
ここでは解説しなかったDMA通信については、以下をご参照ください。