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

  • 2021.01.08
  • LL
STM32 LLでUARTしてみる 受信(割り込み編)

皆さま こんにちは。

今回は LL UART通信の受信を割り込みを使って行ってみます。

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

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

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

割り込みを使った受信

送信は
・ポーリング
・割り込み
・DMA
の3パターンについて動作確認しましたが、UART受信は以下の理由から割り込み1択にしました。

ポーリングによる受信は、取りこぼしやすくなることや他の処理に影響するので実用的ではありません。
また、DMAによる受信はエラー処理が複雑になるので取り上げません。

使用するプロジェクト

STM32 LLでUARTしてみる 送信(DMA編) でつくったプロジェクトを使います。

受信処理をこのプロジェクトに追加して、送信はDMAを使うことにします。

通信仕様

・パソコンから5バイト送る

・受信処理

エラーなく5バイトを受信したら、以下を返信する。

Data received. CR LF

コーディングする

main.c

MX_USART2_UART_Init()関数の最後に LL_USART_EnableIT_RXNE() を1行追加する

EnableIT は割り込みを有効にする の意味
RXNE は Rx Not Empty の意味 受信が空でないということなので

データを受信したら割り込みが入るようになります。

// 送信完了割り込みを有効にする
LL_DMA_EnableIT_TC(DMA1, LL_DMA_STREAM_6);
LL_USART_EnableIT_RXNE(USART2); // この1行を追加する

main()関数の前あたりに

/* USER CODE BEGIN 0 */
#define _CR 0x0d
#define _LF 0x0a

uint8_t buffer[] = "Data received.\r\n";
int recvComplete;

void DMA_TransmitData();

void DMA_TransmitData()
{

  LL_DMA_DisableStream(DMA1, LL_DMA_STREAM_6);

  LL_DMA_SetDataLength(DMA1, LL_DMA_STREAM_6, sizeof(buffer));

  LL_DMA_EnableStream(DMA1, LL_DMA_STREAM_6);

  LL_USART_EnableDMAReq_TX(USART2);
}

/* USER CODE END 0 */

while()ループ内


while (1)
{
  if (recvComplete)
  {
    recvComplete = 0;
    DMA_TransmitData();
  }
}

stm32f4xx_it.c

このファイルには割り込みハンドラが書かれています。

USART2_IRQHandler()とその前に以下のコードを書きます。

extern int recvComplete;

void USART2_IRQHandler(void)
{
  static uint8_t buff[128];
  static uint8_t counter = 0;
  /* USER CODE BEGIN USART2_IRQn 0 */
  if (LL_USART_IsActiveFlag_ORE(USART2)) // Over run error
  {
    LL_USART_ReceiveData9(USART2); // 読み捨てる
    counter = 0;
  }
  else if (LL_USART_IsActiveFlag_PE(USART2)) // Parity error
  {
    LL_USART_ReceiveData9(USART2); // 読み捨てる
    counter = 0;
  }
  else if (LL_USART_IsActiveFlag_FE(USART2)) // Framing error
  {
    LL_USART_ReceiveData9(USART2); // 読み捨てる
    counter = 0;
  }
  else if (LL_USART_IsActiveFlag_RXNE(USART2))
  {
    buff[counter++] = (uint8_t)LL_USART_ReceiveData9(USART2);
    if (4 < counter)
    {
      counter = 0;
      recvComplete = 1;
    }
	// 受信処理
  }
  /* USER CODE END USART2_IRQn 0 */
  /* USER CODE BEGIN USART2_IRQn 1 */

  /* USER CODE END USART2_IRQn 1 */
}

プログラム概要

USART2_IRQHandler()はUSART2の割り込みハンドラです。
オーバーラン、パリティ、フレーミングエラーを検出したらデータレジスタを読み捨てます。
それ以外でデータを受信したら counterをインクリメントします。
5バイト受信したら recvComplete を 1 にします。

while()ループ内で recvComplete が 1 になったら DMAを使って返信します。

以下は各エラーの概要です。

オーバーランエラー:
受信バッファに取り込まれたデータを読み出す前に次のデータが入ってきてしまうエラー。

パリティエラー:
パリティの不一致
偶数パリティなのに、奇数であったり、例えばノイズでデータビットが1ビット反転すると起こるエラー。

フレーミングエラー:
ストップビットが所定の位置にないエラー。
フォーマット違いなどで起こることがある。

Teram Termの設定

何度も出てきているので画像は省略します。
以下の要領で設定します。

COMポート : 新しい接続でシリアルを選択し、STLink Virtual COMのポートを選択する。

設定 – シリアルポートより

スピード : 115200
データ : 7bit
パリティ : even
ストップビット : 1bit
フロー制御 : none

端末の設定でローカルエコーにチェックを入れます。

ビルドして動かしてみる

ビルドして実行してみます。
パソコンからTera Termでキーを押して何か5バイト送ってみてください。

パリティを even から odd にするとパリティエラーを検出して、はじいてくれることも確認してみてください。

いかがでしたか?
うまく動きましたか?

お疲れさまでした。

LLカテゴリの最新記事