[組み込み] レジスタ制御しようぜのUART編

# はじめに
これは以下記事の内容の一部なります。

https://qiita.com/T_ksy/items/655214cc34feacfb6d5e
# 設計
基本的な処理が決まったため、次は詳細な設計をしていきたいと思います。

:::note warn
この設計パートでは初期化処理のみ説明します。
その他の処理について大したことないため実装パートにて説明します。
:::

### UARTレジスタ制御モジュールUARTを制御するためのモジュールになります。
今回の用途としては、外部とのデータの通信制御になります。

以下が初期化制御フローになります。
![デバドラ_led制御-UART制御フロー.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3290770/126ee0ce-cb25-282d-47d5-79b5d7ef78f2.png)

何をしているか順に説明していきます。

#### 1\. RCCの設定
こちらの設定はGPIO編にて説明した内容と同じになります。

STM32にはUART機能が複数搭載されています。今回はUART2(USART2)を使用します。
また、UART機能を使うということはGPIOピンのどこかしらを使わないと通信できないですよね。
そのため、GPIO機能に繋がっているバスも有効化する必要があります。
この辺の説明は後でします。
![UART使用時のブロック図.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3290770/f84bd9b7-af7e-b0cc-54d3-fbccc62fce2c.png)
[DS10693 P16]

UART2がAPB1バスで、GPIOがAHB1バスなのでこれらのクロックを有効化します。

今回はGPIOAを使用するため**RCC_AHB1ENR**レジスタの0bit目を設定します。
![UARTのRCC_GPIOクロック設定.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3290770/b54f421d-e7cd-6b2c-aa03-71011f12bf9c.png)
[RM0390 P144]

次にUARTのクロックですが、こちらは**RCC_APB1**レジスタになります。
17bit目がUART2になりますのでこちらを設定します。
![UARTのRCC_UARTクロック設定.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3290770/5727ac2e-0b86-39eb-ce5d-013f6db605c1.png)
[RM0390 P147]

#### 2\. GPIOの設定
次はGPIOの端子設定をしていきます。

ここで重要なのが、GPIOの**オルタネート**機能を使用します。
GPIO端子には単純な入出力モード以外に他機能の専用モードで使用することができます。
今回はUART2のTXとRXが使用したいので、PA2とPA3のAF7が対象になります。
![オルタネートモード説明.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3290770/e67c0dd3-d444-e5e7-5c8e-0892399cdd59.png)
[DS10693 P57]

ではTX(送信)の設定していきましょう。

まずは、GPIO編同様にGPIO_MODERレジスタを設定します。
![GPIOレジスタ設定.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3290770/c5dc178c-e534-34d6-51a0-08bbb3a0e754.png)
[RM0390 P187]

PA2なので4-5bit目が対象で、ここに"10"を設定します。

次に、オルタネート機能の設定をします。
![オルタネートレジスタ.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3290770/277d4b50-e25f-27e0-8a92-42ac415a1220.png)
[RM0390 P192]

ここで一つ注意点があります。このレジスタ、AFRLとAFRHの2つがありますよね。
なぜ2つに分かれているかと言うと、GPIOの端子によって上位と下位で分かれています。
AFRLがGPIO0〜GPIO7までで、AFRHがGPIO8〜GPIO15となっています。

今回はPA2になるため8-11bit目が対象となります。
AF7を使用したいので、設定値は"0111"を設定すればよさそうですね。

最後にGPIO_PUPDRレジスタでプルアップの設定をします。
![UARTのプルアップレジスタ.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3290770/2ce8f891-1b11-9d7d-eb84-0e960f9d98e4.png)
[RM0390 P189]

プルアップにしたいので"01"を設定します。

これでTX(送信)の方は完了で、同じ要領でRX(受信)も設定すればOKです。

#### 3\. UARTの設定
ここではuARTの設定をしていきます。UARTの設定というのは、
ボーレート、パリティビットの有無、割り込みなどを設定します。

改めて今回のUARTの仕様を以下に記載しました。
UART仕様
　データビット：8bit
　パリティ：なし
　ストップビット：1bit
　ボーレート：115200

実はこの仕様だとほぼ設定し直すレジスタはありません。ボーレートだけになります。
UART_BRRレジスタを設定するだけになります。
![UART_ボーレートレジスタ.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3290770/4e5d113e-86a8-70a1-5733-735d3b977484.png)
[RM0390 P838]

あれ？なにを設定すればいいんだ？と思ったはずです。
もう一つ見るページがあって、それが以下になります。
![UART_ボーレート設定値.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3290770/003e760f-5d67-776d-3bcd-154da60350ee.png)
[RM0390 P811]

ボーレートの設定値はシステムクロックに依存します。今回システムクロックを変更していため
デフォルトの16MHzになったままです。そのため「fPCLK=16MHz」の図を見ています。
で、今回使用したいボーレートは115200なのでNo7の"8.6875"を設定してあげればよさそうですね。

次に割り込みの設定をします。
今回は受信割り込みを使用するのでその設定をします。
UART_CR1レジスタがUARTの全体的な制御をするものになっています。
![UART_CR1レジスタ.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3290770/a6f4c8ac-e52f-3141-3d6c-a70f5cef9263.png)
[RM0390 P839]

この5bit目の**RXNEIE**というのが受信割り込みを有効にする設定となります。
なのでこれを設定し、その後にGPIO編にもあったNVICの設定をしたら割り込みの設定は完了です。

で、このレジスタは他にも設定が必要にもなります。
2-3bit目の**RE**と**TE**、13bit目の**UE**を設定する必要があります。
REとTEは送信と受信のイネーブル設定になって、UEはUARTを開始する設定になります。
なので、これらのbitに"1"を設定したらOKです。

# 実装

先ほどの設計を踏まえて実装していきます。

### init_uart2:初期化処理
```c
void init_uart2(void)
{
    RCC_TypeDef *pRCC;
    pRCC = RCC;

    GPIO_TypeDef *pGPIOA;
    pGPIOA = BASE_ADDR_GPIOA_PERI;

    USART_TypeDef *pUART2;
    pUART2 = USART2;

    // UART2のクロックを有効化
    pRCC->APB1ENR |= (1 << 17);

    // UART TXピン(GPIOA2)とRXピン(GPIOA3)の設定
    // PA2: UART2 TX PA3: UART2 RX

    // PA2の設定
    // GPIOAのクロックを有効化
    pRCC->AHB1ENR |= (1 << 0);

    // GPIOA2ピンをAFモードに設定(UART2 TX)
    pGPIOA->MODER &= ~(0x3 << 4);
    pGPIOA->MODER |= (0x2 << 4);
    pGPIOA->AFR[0] &= ~(0xF << 8);
    pGPIOA->AFR[0] |= (0x7 << 8);

    // プルアップ設定
    pGPIOA->PUPDR |= (0x1 << 4);

    // PA3の設定
    // GPIOA3ピンをAFモードに設定(UART2 RX)
    pGPIOA->MODER &= ~(0x3 << 6);
    pGPIOA->MODER |= (0x2 << 6);
    pGPIOA->AFR[0] &= ~(0xF << 12);
    pGPIOA->AFR[0] |= (0x7 << 12);

    // プルアップ設定
    pGPIOA->PUPDR |= (0x1 << 6);

    // ボーレートの設定
    pUART2->BRR = 0x8B;  // 115200bps

    // UARTのデータ幅、パリティ、ストップビットの設定
    // デフォルトを使用するので設定不要(8bit, No parity, 1 stop bit)

    // 受信の割り込み有効化
    pUART2->CR1 |= (0x1 << 5);  // RXNEIE割り込み有効化
    NVIC_EnableIRQ(USART2_IRQn);

    // UARTのTXとRXの有効化
    pUART2->CR1 |= (0x3 << 2);  // UARTの送受信有効化

    // UARTの有効化
    pUART2->CR1 |= (1 << 13);
}
```

一点だけ補足しておきます。
ボーレートの設定ですが、"8B"というのは"8.6875"を16進表記したものになります。

### request_dma_start:DMA開始要求処理

```c
void request_dma_start(void)
{
    USART_TypeDef *pUART2;
    pUART2 = USART2;

    // DMAコントローラーに要求を送信
    pUART2->CR3 |= (1 << 7);
}
```
概要：DMAに対して送信開始を要求する。
処理内容：概要と同じなので省略。

### USART2_IRQHandler:割り込みハンドラ
以下に割り込みハンドラも記載します。
※こちらは「stm32f4xx_it.c」ファイルに記載しています。

```c
void USART2_IRQHandler(void)
{
    USART_TypeDef *pUART2;
    pUART2 = USART2;

    // ステータスレジスタで受信可能か確認
    // 受信可能ならば、DRからデータを取得
    if (pUART2->SR & (1 << 5)) {
        uint32_t data = pUART2->DR;
        set_led_data(data);
    }

    clear_usart2_pending_bit();
}

void clear_usart2_pending_bit(void)
{
    USART_TypeDef *pUART2;
    pUART2 = USART2;

    if (pUART2->SR & (1 << 5)) {
        // 受信フラグをクリア
        pUART2->SR &= ~(1 << 5);
    }
}
```

概要：UARTの受信割り込み処理を行う
処理内容：
以下のようなことをやっています。
1\. UARTのステータスレジスタでリードデータが入っているかを確認する。
2\. UARTのデータレジスタからデータを取得し、LED情報に設定する。
3\. 受信フラグをクリアする。

# 終わりに
これにてUARTのレジスタ制御モジュール作成は完了となります。