STM32 汎用I/Oポートのプログラミング

STM32(F103C8T6)のI/Oポートの使用方法・プログラミングについて自分の備忘録としてまとめておく。

使用したのは STM32F103C8T6 の安価なボード、eBayで購入したものである。
パソコンとは ST-LINK V2 を経由してUSBで接続した。開発環境はCooCox CoIDE Ver.1.7.8 で、ツールチェーンは GNU Tools ARM Embedded を使用した。
ボードとの接続は下図のとおりである。

A0を「汎用出力オープンドレイン」とし、LEDはHighで消灯、Lowで点灯する。
A1を「プルアップ/プルダウン付きの入力」とし、内部でプルアップしておき、
スイッチONでLowレベル、OFFでHighレベルとなる。
スッチを押すとLEDが点灯する単純なプログラムである。ソースは次のとおり。

#include "stm32f10x.h"

int main(void)
{
    //ポートAのクロックを有効にする
    RCC->APB2ENR |= RCC_APB2ENR_IOPAEN;
    //ピンA0を出力に設定する MODE:10 CNF:01
    GPIOA->CRL |= GPIO_CRL_MODE0_1;
    GPIOA->CRL &= ~GPIO_CRL_MODE0_0;
    GPIOA->CRL &= ~GPIO_CRL_CNF0_1;
    GPIOA->CRL |= GPIO_CRL_CNF0_0;
    //ピンA1を入力に設定する MODE:00 CNF:10
    GPIOA->CRL &= ~GPIO_CRL_MODE1;
    GPIOA->CRL |= GPIO_CRL_CNF1_1;
    GPIOA->CRL &= ~GPIO_CRL_CNF1_0;
    //ピンA1をプルアップ
    GPIOA->ODR |= GPIO_ODR_ODR1; //プルアップ
    //GPIOA->ODR &= ~GPIO_ODR_ODR1; //プルダウンの場合

    while(1) {
        if(!(GPIOA->IDR & GPIO_IDR_IDR1)){
            // LED ON
            GPIOA->ODR &= ~GPIO_ODR_ODR0; //A0:Low
    	} else {
            // LED OFF
            GPIOA->ODR |= GPIO_ODR_ODR0; //A0:High
    	}
    }
}

I/Oの設定手順は以下のとおり。
《出力》
1.クロックを有効にする
  APB2 ペリフェラルクロック有効レジスタ(RCC_APB2ENR)
2.モードと機能の設定を行う
  ポート設定レジスタ(下位 GPIOx_CRL)または(上位 GPIOx_CRH)(x=A..G)
3.出力
  ポート出力データレジスタ(GPIOx_ODR)(x=A..G)

《入力》
1.クロックを有効にする
  APB2 ペリフェラルクロック有効レジスタ(RCC_APB2ENR)
2.モードと機能の設定を行う
  ポート設定レジスタ(下位 GPIOx_CRL)または(上位 GPIOx_CRH)(x=A..G)
3.プルアップ/プルダウンの設定を行う
  ポート出力データレジスタ(GPIOx_ODR)(x=A..G)
4.入力
  ポート入力データレジスタ(GPIOx_IDR)(x=A..G)


出力に必要なレジスタの設定

1.“APB2 ペリフェラルクロック有効レジスタ(RCC_APB2ENR)”
  ポートAのクロックを有効にする


RCC_APB2ENRレジスタの指定は RCC->APB2ENR とし、ポートAのビットを指定する RCC_APB2ENR_IOPAEN とORをとることでポートAのクロックが有効になる。

    RCC->APB2ENR |= RCC_APB2ENR_IOPAEN;

2.“ポート設定レジスタ(下位 GPIOx_CRL)または(上位 GPIOx_CRH)(x=A..G)”
  ポートのモードと機能を指定する

ピンA0~A7はGPIOx_CRLを、ピンA8~A15はGPIOx_CRHを使う。

GPIOA_CRLレジスタの指定は GPIOA->CRL とし、ビット指定 GPIO_CRL_MODE0_1 と GPIO_CRL_MODE0_0 でピンA0のモードを指定する。さらに、GPIO_CRL_CNF0_1 と GPIO_CRL_CNF0_0 でピンA0の機能を指定する。
MODE0を“10”(出力モード 2MHz)にするには、GPIO_CRL_MODE0_1=1 GPIO_CRL_MODE0_0=0 にビット設定する。

    GPIOA->CRL |= GPIO_CRL_MODE0_1;
    GPIOA->CRL &= ~GPIO_CRL_MODE0_0;


CNF0を“01”(汎用出力オープンドレイン)にするには、GPIO_CRL_CNF0_1=0 GPIO_CRL_CNF0_0=1 にビット指定する。

    GPIOA->CRL &= ~GPIO_CRL_CNF0_1;
    GPIOA->CRL |= GPIO_CRL_CNF0_0;


3.“ポート出力データレジスタ(GPIOx_ODR)(x=A..G)”
  ビットをセット/リセットする


ビットをセット/リセットすることにより、対応するピンを Low/High にする。ポートAのGPIOA_ODRレジスタ指定はGPIOA->ODRとし、ビット指定はGPIO_ODR_ODR0~GPIO_ODR_ODR15を用いる。

            GPIOA->ODR |= GPIO_ODR_ODR0; //A0:High
            GPIOA->ODR &= ~GPIO_ODR_ODR0; //A0:Low



入力に必要なレジスタの設定

1.“APB2 ペリフェラルクロック有効レジスタ(RCC_APB2ENR)”
  クロックを有効にする

出力と同じ設定を行う。ポートを有効にする設定でプログラムの最初に有効にしておけば、そのあとは設定する必要はない。

2.ポート設定レジスタ(下位 GPIOx_CRL)または(上位 GPIOx_CRH)(x=A..G)
  モードと機能の設定を行う

ピンA1を入力に設定するには、MODE1を“00” とする。ビット指定は、GPIO_CRL_MODE1_1=0 GPIO_CRL_MODE0_1=0 とするか、GPIO_CRL_MODE1 で2ビット分をまとめて指定する。
入力機能を“プルアップ/ブルダウン付き”にするには、CNF1を“10”とする。ビット指定は、GPIO_CRL_CNF0_1=1 GPIO_CRL_CNF0_0=0 とする。

    //ピンA1を入力に設定する MODE:00 CNF:10
    GPIOA->CRL &= ~GPIO_CRL_MODE1;
    GPIOA->CRL |= GPIO_CRL_CNF1_1;
    GPIOA->CRL &= ~GPIO_CRL_CNF1_0;


3.ポート出力データレジスタ(GPIOx_ODR)(x=A..G)
  プルアップ/プルダウンの設定を行う

ポートを入力として用いる場合、端子の電圧レベルを安定させるためにプルアップもしくはプルダウンを行う。STM32には内部にプルアップ/プルダウン回路が内蔵されており、入力モードにおいてはポート出力データレジスタのビットをセットするとプルアップ、リセットするとプルダウンされるようになっている。

ピンA1にはスイッチを接続し、スイッチONでGNDに接続されLowレベルになるので、スイッチOFF状態ではHighレベルになるようプルアップが必要である。ポートAのピンA1をプルアップするにはGPIOA_ODRレジスタのODR1ビットをセットする。

    //ピンA1をプルアップ
    GPIOA->ODR |= GPIO_ODR_ODR1; //プルアップ
    //GPIOA->ODR &= ~GPIO_ODR_ODR1; //プルダウンの場合


4.ポート入力データレジスタ(GPIOx_IDR)(x=A..G)
  入力を行う


ピンA1を入力するには、GPIOA_IDRレジスタのGPIO_IDR_IDR1ビットを読む。

        if(!(GPIOA->IDR & GPIO_IDR_IDR1)){



備考
プルアップ/プルダウンの設定について、リファレンスマニュアルでは次表のように記述されている。

表の“PxODRレジスタ”がこの表以外、リファレンスマニュアルに記述がなく、プルアップ/プルダウンのやり方が分からなかった。ネット検索で探したが見つけることができず途方に暮れていた。ネットで見つけたサンプルコードをデバッガで実行してレジスタの変化をウオッチして、表の“PxODRレジスタ”は“GPIOx_ODRレジスタ”であることが分かった。悩んでから解決まで2日ほど費やした。
 
 


シェアする

  • このエントリーをはてなブックマークに追加

フォローする