STM32いじってみた(6) UART編

今回は USART 機能を使って、UART 通信を実装していきたいと思います。

UART とは(ざっくりと)

この通信方式はシリアル通信のうちの1つです。電源やGND線以外に使う(必須な)信号線は TXD と RXD の2線のみです。SPI 通信や I2C のようにマスタ・スレーブの区別はなく、スレーブ選択も出来ません。(…多分。)

メジャーなデータ転送方式としては 調歩同期式クロック同期式 があります。STM32 では別の言い方があったかどうか正直覚えてないのですが、それは許してください。なおこの2つの呼び方はルネサス社の呼称に合わせました。

線の接続

上で述べたように、TXD と RXD の2線を使います。TXD は データ送信(Transmit)用、RXDはデータ受信(Receive)用の線です。2デバイス間では、一方が送信となったら他方が送信となりますので、一方の TXD を 他方の RXD につなぐ、といったクロス配線をする必要があります。

ということで書き込み用配線以外に以下のピンを接続する必要があります。ただし LPC11U35 のUSBシリアル変換機能は貧弱なので別途 FT232RL 等の USBシリアル変換モジュールを利用することをおすすめします。

STM32側のピン ピン番号 FT232RL側のピン名
USART1_TX 19 RXD
USART1_RX 20 TXD

はーい、それじゃあ面倒くさいのでコードだけ出しまーす

static void usart_io_init(void) {
    // GPIO as Tx and Rx
    // NOTE: The index for AFR is vailable only in 0 or 1.
    //       In detail, you should refer in the programming reference guide.
    RCC->AHBENR |= RCC_AHBENR_GPIOAEN;
    GPIOA->MODER |= (GPIO_MODE_AF_PP << GPIO_MODER_MODER9_Pos); // Alternate function in PA9
    GPIOA->AFR[1] |= (GPIO_AF7_USART1 << (4 * (9 - 8))); // alternate function select in high resistor
    GPIOA->PUPDR |= (GPIO_PULLUP << GPIO_PUPDR_PUPDR9_Pos);
    GPIOA->OSPEEDR |= (GPIO_SPEED_HIGH << GPIO_PUPDR_PUPDR9_Pos);

    GPIOA->MODER |= (GPIO_MODE_AF_PP << GPIO_MODER_MODER10_Pos); // Alternate function in PA10
    GPIOA->AFR[1] |= (GPIO_AF7_USART1 << (4 * (10 - 8))); // anternate function select in high resistor
    GPIOA->PUPDR |= (GPIO_PULLUP << GPIO_PUPDR_PUPDR10_Pos);
    GPIOA->OSPEEDR |= (GPIO_SPEED_HIGH << GPIO_PUPDR_PUPDR10_Pos);
}

// Tx/Rx Baud rate = f_ck / USARTDIV (16x over sampling)
// SET_BIT() and CLEAR_BIT() macros are available in stm32f3xx.h .
void usart_init(uint32_t baudrate) {
    RCC->APB2ENR |= RCC_APB2ENR_USART1EN;
    RCC->CFGR3 |= RCC_CFGR3_USART1SW_SYSCLK; // system clock == usart1 clock

    // In this project, word length is set to 8bit.
    USART1->CR1 &= ~USART_CR1_OVER8; // not OVER8
    USART1->BRR |= 64e6 / baudrate;
    usart_io_init();
    USART1->CR1 |= USART_CR1_TE | USART_CR1_RE; // transmitter & receiver enable

    USART1->CR1 |= USART_CR1_UE; // enable USART1
}

特にハマりポイントはありませんでしたね〜〜。言うならば、オルタネート機能選択がよくわからないことですね。上で GPIO_AF7_USART1 とやっていますが、GPIO_AF …何だ?と止まりました。そこは適当にマクロ名の補完機能から察しましたが。これどうやって確認するんですかねぇ??

またここで一つの Tips を示しますと、printf の自作が簡単になるように vsprintf() を使っていることです。これは可変長配列を用いて printf 的にフォーマット指定子に従って文字列を出力できる関数なのです。これは知っておくといろいろな所で便利ですよ。vsprintf を使うために stdio.h が、可変長配列を用いるために stdarg.h が必要になります。