STM32F3Discover GPIO

マイコンをやったら最初にやること。LEDの点灯です。
まずはこれからやってみましょう。

[ GPIO ]
マイコンでは、入力したり出力したりするもののことをI/Oといいます。LEDをつけるときもIOを使います。
特にARMではI/OをGPIOと呼んでいます。General Purpose IO(汎用的なIO)という意味らしいです。
STMDiscoveryのドキュメント023594.pdfにはこんな表があります。
これはボード上でどのピンが何につながっているかです。これをみれば基板にある8このLEDがマイコンのどこにつながってるかわかります。

どやらLEDはPE8~PE15につながってますね(PE15はスクショの関係で切れちゃいましたがPE14の下にありあす。ごめんね!)
PEって何かというとGPIOEの略です。
マイコンにはたくさんのピンがあって、それのONやOFFをプログラムから制御できます。それができてこそマイコンだよね。
しかし、すべてのピンを ピン87番とかピン111番というふうに名前をつけて制御することはできません。どうしてもグループ化する必要があるのです。
このマイコンではすべてのピンをグループA~グループFまでの6個のグループに分けてあります。
GPIOA
GPIOB
GPIOC
GPIOD
GPIOE
GPIOF
そして、それぞれが15個のピンを制御します。
LEDにつながっているのは、グループとそのグループの中の番号で言うと、グループFの8番から15番ということですね。
だから、このピンをONにしてLEDをつけたりOFFにしてLEDを消すには、
プログラム的にはグループEの8番をONにしたりOFFにしたり と言ったプログラムをかくことになります。
では、実際にやってみましょう。

[ レジスタ操作 ]
STM32F30シリーズで、GPIOの出力状態を制御しているのはODRというレジスタです。
出力状態をレジスタで制御するというのはどういうことでしょうか。
referencepdfの22558の8.2.6にこんな表があります。

これがODRというレジスタです。32ビット分ありますが、15bitから0bit目までがそれぞれそのGPIOの0~15の出力状態の設定になってます。
どういうことかというと、例えば、GPIOEの8にはLEDがつながってますね。このLEDを点けるにはGPIOEのODRレジスタの8ビット目を1にすればいいんです。
すると、「GPIOEの8は出力状態が1ね」と設定したことになります。すると、GPIOEの8番ピンには電圧がかかり、LEDがつきます。
逆に0にしたらLEDはつきません。GNDに接続されたのとおなじになります。

今回のミッションはGPIOEの8番につながったLEDをつけることとします。すると、GPIOEのODRには
0x0100
を書き込めば、ちょうど8bit目だけ1になりここのLEDだけつきますね。
これをプログラムするとこういう感じになります。

#include “stm32f30x.h”

void SystemInit(void)
{

}

int main(void)
{
GPIOE->ODR = 0x0100;
while(1){
}
}

余計なinclude文が出てきました。
これはMDK-ARMにセットで入ってきたもので、STM32F30x系のマイコンで、どのレジスタがどこにあるとかってのが定義されています。
GPIOEのODRにアクセスしたいときは
GPIOE->ODR ってすればアクセスできます。ここに値を書きたい場合は
GPIOE->ODR = 0;
みたいにすればOKです。今回はここに0x0100を書きたいので、main関数始まってすぐに
GPIOE->ODR = 0x0100;
を実行します。

ただ、このプログラムだけだとLEDはつきません。
GPIOEはピンへの出力ができますが、入力もできます。つまり、逆にピンに電圧がかかってるかどうかを01で知ることもできるわけです。
つということは、ピンごとに入力なのか、出力なのかを設定するところがどっかにあるわけです。そして、それはマイコンの電源投入後にはすべて入力になっているのです!
これじゃあODRに1をセットしても出力されません。
それを設定するレジスタを紹介します。というか、この際なので、GPIOに関係したレジスタを全部紹介しましょう。

– MODER  ピンごとに デジタル入力 アナログ入力 デジタル出力 AlternativeFunctionなのかを決める
– OTYPER  出力モードがプッシュプルか、オープンドレインかを選ぶ
– OSPEEDR  ピンごとの速度設定
– IDR  デジタル入力状態
– ODR  デジタル出力状態
– BSRR  ODRのbitwise write access
– LCKR  このGPIOの設定ロック
– AFRH  8~15pinのalternativefunction
– AFRL  0~7pinのalternativefunction

ピンには4つのモードがあります。今回使いたいにはデジタル出力ですが、他にデジタル入力とアナログ入力 があります。
アナログ入力はA/Dで使うやつです。そして、AlternativeFunctionというのは、ピンごとにGPIO以外の機能を接続することがあるのですが、それがalternativeFunctionです。GPIOじゃなくてこっちでつかうときはMODERをこれにして、AFRHやAFRLの4bitを使って、alternativeFunctionを設定します。
今回は関係ないので省略。
今回関係あるのだけにすると

MODER
OTYPER
OSPEEDR
です。そしてそれぞれこのような設定があります。

MODER
00 input
01 output
10 alternative
11 analog input

OTYPER
0 push-pull
1 opendrain

PUPDRは
00 none
01 pull up
10 pull down
11 reserved(00とほぼ同じだが基本使わない)

MODERとPUPDRはそれぞれ2bitで1つのピンの設定をします。OTYPERはODRと同じように1bitで1つのピンです。
MODERは出力にしたいのでGPIOEの8を01にしなきゃいけません。
OTYPERは出力タイプです。プッシュプルとは1なら電源の+が、0ならGNDが出力されるということです。オープンドレインは0と1でハイインピーダンスとGNDを出力するものです。今回はプッシュプルでいいので0にしましょう。
PURDRはポートごとのプルアッププルダウンをするものです。今回はいらないので00でよさそうです。
GPIOEの8に対していままでの設定をします。
出力モード・出力タイプはプッシュプル・プルアップダウンなし・そして出力はON

GPIOE->MODER = 0x00010000;
GPIOE->OTYPER = 0x0000;
GPIOE->PUPDR = 0x00000000;
GPIOE->ODR = 0x0100;

するとこのようになりますね。
これは、GPIOEの8番品以外も設定してることになります。0を書き込んでるから0を設定してることになります。
ただ、MODERが00ということはinputなので、まぁ悪さをすることはないと思います。
さて、これでGPIOEの8番を出力に出来ました。

[ クロックの設定 ]
最後にもう1つだけONにしなきゃいけない部分があります。クロックです。
ARMはそもそも少ない電気で動くようにと設計されたものです。このSTM32F3もなるだけ少ない電気で済むように設計されています。
余計な部分で電気を食わないように。
マイコンにおいて電気が消費されるのは基本的にクロックが来た時です。早く動かせばそれだけ電気を食うし遅ければそれだけ電気を食いません。そして、クロックがなければ動かないので電気を食わないわけです。
このSTM32FはGPIOを含め、ほぼすべてのモジュールに”クロックが来ていません”。設定しないとクロックが来ない->動かない のです。
すごいよね。
もちろんODRとかのレジスタに値を書き込むことはできますが、この値がちゃんと反映されてピンから出力されるには最低でも1回はクロックが来ないとダメです。
クロックのタイミングでレジスタから実際の出力になるわけですから。
というわけで、モジュールを使いたかったら使いたいモジュールのクロックをONにしないといけないわけです。

ちなみに、STM32F3にはAHBとかAPB1とかいろいろなクロックの配線があってそれぞれ速度を減速できるようになってます。
例えばAHBはCPUと同じ。APB1はCPUの半分とかができます。遅くすればそれだけ電気を食わないので不要な部分は速度を落とす なんてことができます。
それぞれのモジュールはつながってる場所が決まってます。GPIOはすべてAHBにつながっています。
RCCのAHBにおいて、GPIOEをONにしましょう。

RCC->AHBENR |= RCC_AHBENR_GPIOEEN;

これでOKです。さっきのドキュメントには

こうやってかいてあります。これがAHBENRレジスタで、AHBというクロックの回線がつながってるモジュールそれぞれのONOFFになってます。
GPIOEは21bit目ですね。reset後は0つまりOFFになっています。21bit目を0から1にすればOKです。
さっきのヘッダファイルには
RCC_AHBENR_GPIOEEN
というのが用意してあって、これは21bit目だけ1となるような数値です。
これをAHBENRにorします。つまり今AHBENRですでに1になってるものはそのままに、追加で21bit目を1にします。
それが

RCC->AHBENR |= RCC_AHBENR_GPIOEEN;

です。

これでGPIOEの8をONにできます。な、、、、ながいみちのりでしたね。

#include “stm32f30x.h”

void SystemInit(void)
{

}

int main(void)
{
// connect AHB
RCC->AHBENR |= RCC_AHBENR_GPIOEEN;
GPIOE->MODER = 0x00010000;
GPIOE->OTYPER = 0x0000;
GPIOE->PUPDR = 0x00000000;
GPIOE->ODR = 0x0100;
while(1){
}
}

完成品はこんな感じです。これを動かしてみましょう。
前回使ったMDK-ARMのLoadを押してプログラムを転送し、基板にあるリセットボタンを押せば動きますが、今回は試しにデバッグ機能を使います。まず、このプログラムを書いたらBuildをおしてちゃんとビルドします。
つぎにデバッグボタンを押します。

すると警告が一度出ますがOKおしちゃいます。無料だと32KBまでだよって警告です。
そして、Runボタンを押して実行します。

これで実行できます。
実行すると、基板上のLD4と書かれた青色のLEDが光ると思います。
光ればOK。
まとめ。
・すべてのI/OピンはA~Fの6つのGPIOで管理されている。
・出力をONOFFするには対応するGPIOのODRレジスタを0や1にする
・出力するには出力設定や出力モード切替が必要
・GPIOなどのモジュールを使うにはクロックをONにする必要がある。

コメントを残す