組み込み開発初心者である筆者は、「GPIOについて記事を書いてほしい」という依頼をきっかけにGPIOの学習を始めました。本記事は、LEDを一つ点灯させるために試行錯誤する中で学んだ内容や気づきを、備忘録としてまとめたものです。
本記事では、マイコンを使った開発において最も基本的なペリフェラルの一つであるGPIO(General Purpose Input/Output)の使い方を解説します。
GPIOは、LEDを点灯したり、スイッチの状態を読み取ったり、センサからの信号を受け取ったりと、マイコンと外部回路をつなぐための組み込みシステムの基盤となっています。
一方で、実際のマイコン開発において、「GPIOを使う」と言っても、単にプログラムを書くだけではありません。マイコンには多数のピンが存在し、それぞれのピンにはGPIO以外にもタイマや通信インターフェースなどの機能が割り当てられています。
そのため、
を適切に行う必要があります。
今回はFRDM-MCXA153を題材に、MCX A153のピン構成やPinMUXの仕組みを確認しながら、Pins Tool上でGPIO設定を行い、最終的にはブレッドボード上に接続したLED点滅のデモンストレーションを紹介します。
FRDM-MCXA153にはMCXA153VLHという型番のマイコンが搭載されています。このマイコンはLQFP 64パッケージを採用しており、全部で64本のピンが存在します。そのうち52本がGPIOとして利用可能です。残りは電源端子(VDD/VSS)やUSB端子、アナログ専用端子などGPIOとして利用できない端子で構成されています。
ただし、「52本のGPIOがある」といっても、52本のGPIO専用ピンが用意されているわけではありません。GPIOとして利用可能なピンの多くは、UARTやSPI、I²C、タイマなどの周辺機能と共有されています。そのため、実際にGPIOとして利用する際には、PinMUX機能を使い、そのピンをGPIOとして動作させるための設定が必要になります。
MCX A153のピン構成をデータシートから確認してみます。54ページ以降に各ピンに割り当て可能な機能が一覧で記載されています。
例えば、Pin Name :P1_8 の「Pinmux Assignment」を見ると、6つの機能候補があります。GPIOは”ALT0 - P1_8”が該当します。他にも”ALT2 - LPUART1_RXD”はUARTの受信端子(RXD)、”ALT3 - LPI2C0_SDA”はI²Cデータ線(SDA)として使用することを意味します。
このように1本のピンに対してGPIOだけでなく、UARTやI²C、タイマなどの複数の機能が割り振られていることがわかります。
1. ピン機能の選択(PinMUX)
前節で確認したように、P1_8にはGPIO、UART、I²Cなど複数の機能候補が存在します。しかし、同じピンを同時にGPIOとUARTとして利用することはできません。
そこで一般的なマイコンには PinMUXという仕組みが用意されています。
PinMUXは、1本の物理ピンと内部ペリフェラルを接続するための切替スイッチのようなものです。
例えばP1_8には6つの接続先候補がありました。PinMUXによってGPIOを選択すると、P1_8はGPIOとして利用することができるようになります。
2. ピンの電気的特性を設定する
ピンには機能だけでなく、電気的な振る舞いも設定できます。 代表的な設定として、
・Pull-up(プルアップ)
・Pull-down(プルダウン)
・Drive Strength(ドライブ強度)
・Open Drain(オープンドレイン)
などがあります。 例えばスイッチ入力ではプルアップ抵抗を有効にすることが多く、LEDや高速信号を駆動する場合にはドライブ強度を調整することがあります。 GPIOとして使用する場合でも、アプリケーションに応じた適切な電気的設定を行うことが重要です。
本記事ではこの電気的特性に関する詳細な説明は割愛します。
3. GPIOの入出力方向を設定する
最後に決めるのが信号の流れる方向です。GPIOには大きく分けて2つの動作モードがあります。
・Input(入力) – 外部から信号を受け取る
・Output(出力) – 外部へ信号を出力する
Input・Outputとはマイコン内部で何が起こっているのでしょうか?
MCX A153は3.3Vで動作するマイコンです。そのためGPIOピンは、基本的にLow(約0V)とHigh(約3.3V)の2つの状態を扱います(なお、MCX A153の動作電圧範囲は1.71V〜3.6Vであり、FRDMボードでは3.3Vが採用されています)。
|
GPIO出力値 |
ピン電圧 |
|
Low (0) |
約0V |
|
High (1) |
約3.3V |
例えば特定のGPIOピンをOutputに設定し、外部にLEDを接続した場合、High(約3.3V)にするとGPIOとGNDの間に電位差が生じ、LEDに電流が流れ、Low(約0V)の状態にするとGNDとの電位差がなくなるので電流が流れなくなります。つまり、LEDの”点滅”はGPIOピンの電圧をHigh(1)とLow(0)の間で切り替えることで点滅と消灯という動作を繰り返していることになります。
一方、InputではGPIOピンの状態をマイコンが監視します。例えば外部回路から約3.3Vが入力されればHigh(1)、約0Vが入力されればLow(0)として認識します。
ここまで説明したピンの機能選択・電気的特性の設定・入出力設定はPins Tool(Pins ToolはNXPが無償提供しているConfig Toolsに含まれます)を用いてGUI上で設定することが可能です。
ここまでで、GPIOを利用するためにはPinMUX設定や入出力方向の設定が必要であることが分かりました。
続いて今回のデモンストレーションを想定し、MCUのピンがFRDM-MCXA153ボード上のどこに接続されているのかを確認しておきましょう。
Schematics(回路図)を確認し、前章で例として取り上げたピン "P1_8"はどこに引き出されているのかを確認します。
回路図の8ページを見てみると、P1_8はFRDM-MCXA153上にあるArduinoヘッダー: J2のD18に接続されていることがわかります。
では、Arduinoヘッダー J2のD18とはどこでしょうか?
続いてBoard User Manualを確認します。
6ページ目にボードに搭載されているコネクタの外観図が載っており、ArduinoヘッダーJ2のD18はどこかを特定することができました。
今回は勉強のため、D18ピンからブレッドボードを経由してLEDを外部接続しますが、ブレッドボードやLEDをお持ちでない場合は、FRDM-MCXA153のボード上に搭載されているRGB LEDを活用することができます。
ただし一点注意があります。ボード上のRGB LEDを使用する場合はLEDのアノード側(+)がVDD_BOARD(3.3V)に接続されており、カソード側(-)がGPIOに接続されています。そのため、先ほどの外部接続したLEDとは逆でGPIOをHigh(1)にするとGPIO側も約3.3Vとなり、LED両端の電位差がほとんどなくなるためLEDは消灯します。
一方、GPIOをLow(0)にするとLED両端に電位差が生じて電流が流れ、LEDは点灯します。
回路図でそれぞれのピンを確認すると
に対応しています。これらのPinMUX設定や入出力設定を行うことでボードに搭載されているLEDを使った動作を確認することもできます。
このように回路図やBoard User Manualを使って、マイコン内部の物理ピンがボード上のどこに接続されているかを確認することができます。
この章では、MCUXpresso Config Toolsの Pins Tool を使用してGPIOの設定を行い、ブレッドボード上に外部接続したLEDを制御してみます。
デモンストレーションで使用した備品
・FRDM-MCXA153
・ブレッドボード
・LED
・抵抗
・ジャンパ線
また今回はVS Code環境にてMCUXpresso SDKとConfig Toolsをインストール済みという前提でデモンストレーションを進めます。
※MCUXpresso SDKとConfig Toolsのインストールがお済みでない方はこちらのブログをご参照ください。
注意:ブログ内ではFRDM-MCXN947のSDKをインストールしていますが本記事においてはFRDM-MCXA153のSDKをインストールしてください。
手元に品番不明の赤色LEDと緑色LEDがあったので、まずは赤色LEDの点灯から試してみます。抵抗は390Ωのものがありました。赤色LEDの順方向電圧(Vf)は一般的に1.8~2.2Vのため、仮に2.0VとしてLEDに流れる電流値を求めます。
マイコンの動作電圧は3.3Vです。Vf 2.0Vと抵抗390Ωを用いると、オームの法則から以下のように電流値が求められます。なおLEDには最大順方向電流(Ifmax)が規定されており、多くの汎用LEDでは20mAと言われています。20mAを超える電流が流れると破損する可能性があるので抵抗値にはご注意ください。
ボードとブレッドボードの配線
はじめに配線を行います
FRDMボード上では、先ほど特定した ArduinoヘッダーJ2の"D18"と"14 GND"を使用します。
以下の図はBoard User Manualを参照しています。
以下の動画を参考に配線してください。
サンプルコードのインポート
続いて、FRDM-MCXA153のSDKからサンプルコードのインポートへ進みます。
左側のパネルから「Import Example From Repository」をクリックしてください。
右側に表示された各タブ内で、「Repository」ではインポートしたFRDM-MCXA153のSDKを選択、「Board」はFRDM-MCXA153を選択してください。
「Template」は、「driver_examples/gpio/gpio_led_output」を使用します。
任意のToolchainを選択して、「Import」をクリックしてください。
Importが完了すると左側のパネルのProjectsに追加されます。
ソースコード gpio_led_output.cを確認します。
今回は、Pins Toolを用いてGPIOの入出力設定を行いたいので、ソースコード側から赤枠で囲んだGPIO出力設定に関する記述を削除します。
Pins ToolでGPIOの設定を行う
続いてConfig Toolsを開きます。Project上で右クリックして「Open with MCUXpresso Config Tools」を選択してください。少し待つとConfig Toolsが立ち上がります。
Config Toolsが開いたらまずは右側のパネルにあるOverviewよりPinsを選択します。
これでPins Toolが開いた状態になりました。
ピンP1_8を有効にします。
P1_8をクリックすると、下記画像のように別のWindowが開くので、ここから「GPIO1:GPIO,8(P1_8)」を探して✓を入れてください。
✓を入れると同時に下記のWindowが表示されますがNoで閉じていただいて問題ありません。
ここまで完了するとPins Tool下部のRouting DetailsにP1_8が追加されます。
続いてGPIOの入出力設定を以下のように変更します。
#38(P3_12)のピンをOutput → Not Specifiedへ、#2(P1_8)のピンをNot Specified → Output へ。
#38のGPIO initial stateにエラーが出ますので、Logical 0→n/aへ変更してください。
ここまで完了したらサンプルコードを書き換えます。まずはConfig Toolsの画面左上にあるUpdate Codeをクリックしてください。
その後Windowが表示されます。ここで必要に応じてコードの変更点を確認することができます。変更が生じたファイルには「change」の記載があります。
VS Codeに戻ると、画面上部に3つのチェックボックスが表示されているので✓が入った状態でOKをクリックします。
少し時間が経つと、ソースコードへの変更が完了します。
続いてソースコード gpio_led_output.cよりGPIOの制御対象を変更します。
gpio_led_output.cを開くと、
以下の記述があります。
while (1)
{
delay();
GPIO_PortToggle(BOARD_LED_GPIO, 1u << BOARD_LED_GPIO_PIN);
}
GPIO_PinInit()およびGPIO_PortToggle()の中身を以下のように変更します。
ここではP1_8を制御対象として指定しており、関数が呼ばれるたびにP1_8の状態がHigh(1)とLow(0)の間で切り替わります。
while (1)
{
delay();
GPIO_PortToggle(GPIO1, 1u << 8);
}
さらに詳しく:GPIOピンは Px_y という形式で表記されます。ここで x はGPIOポート番号、y はそのポート内のビット位置を表します。例えば P1_8 は「GPIOポート1の8ビット目」を意味します。
コード中の
GPIO_PortToggle(GPIO1, 1U << 8);において、
GPIO1はGPIOポート1を表し、1U << 8は8ビット目だけを1にしたビットマスクです。1U << 8 ↓ 0000 0001 0000 0000 (2進数)となり、GPIOポート1の中の8ビット目のみを反転(HighとLowを切り替える)させることができます。
PCとFRDM-MCXA153を接続します。
デバッグ(ビルド&書き込み&アプリケーションの実行)します。
デバッグのプロセスが完了したら、プログラムがブレイクポイントで止まっているので、画面上部のアイコン内の"|▶"をクリックします。
LEDが点滅を開始します。
ところで、このLEDはGPIOからHigh(1) , Low(0) どちらを出力したときに点灯しているのでしょうか?先ほどはHigh(1)を出力したときに点灯していると言及しましたが、本当か検証してみます。
以下が先ほど使用したコードです。
while(1)は無限ループを意味し、波括弧{}の中の処理を繰り返し実行します。
また、delay()は一定時間待機するための関数です。GPIO_PortToggle()はGPIO制御関数なので、High(1)とLow(0)を反転します。
while (1)
{
delay();
GPIO_PortToggle(GPIO1, 1u<<8); }
}
しかしながら、このコードではLEDがHigh(1)のときに点灯しているのか、Low(0)のときに点灯しているのかがわかりません。
そこで異なる関数GPIO_PinWrite() を使用して、GPIOの状態を明示的に制御します。
具体的には以下のようにHigh(1)の状態でdelay()1回分待機し、その後Low(0)の状態でdelay()5回分待機するコードへ変更します。これでLEDの消灯時間のほうが長くなるはずです。
while (1)
{
GPIO_PinWrite (GPIO1,8U ,1);
delay();
GPIO_PinWrite(GPIO1,8U ,0);
delay();
delay();
delay();
delay();
delay();
}
デバッグを実行し、画面上部のアイコン内の"|▶"をクリックします。
狙い通り、LEDの消灯時間のほうが長くなりました。
これによりLEDが点灯しているときにはHigh(1)を出力し、消灯しているときにはLow(0)を出力していることが検証できました。
おさらいすると、GPIOがHigh(1)になると、GPIOピンとして設定したP1_8は約3.3Vになります。GNDとの間に電位差が生じるため、抵抗とLEDを通して電流が流れます。このときLEDの両端には順方向電圧(約2.0V)がかかり、残りの約1.3Vが抵抗にかかります。その結果、LEDが発光します。
一方、GPIOがLow(0)になるとP1_8の電圧は約0Vになります。GPIOピンとGNDの間に電位差がなくなるため電流は流れず、LEDは消灯します。
delay()がたくさん並ぶのはかっこ悪いという方はループ関数も使えます。
while (1)
{
GPIO_PinWrite(GPIO1, 8U, 1);
delay();
GPIO_PinWrite(GPIO1, 8U, 0);
for (int i = 0; i < 5; i++)
{ delay(); }
}
手元にあった緑色のLEDを赤色LEDと並列接続しようと試みました。
緑色の順方向電圧(Vf)は一般的に2.0~2.2Vのため、赤色LEDと同様に仮に2.0Vとして以下のような回路を組みました。
ピンの設定は変える必要がないため、そのまま先ほど使ったコードでデバッグを行ったところ、赤色LEDは点滅しますが緑色LEDは点滅しません。なぜでしょうか?
LEDには、順方向電圧(Vf)を超えると急激に電流が流れ始めるという特性があります。そのため赤色LEDと緑色LEDを単純に並列接続すると、Vfの低いLEDに電流が集中し、もう一方はほとんど点灯しないことがあります。つまり今回の場合は赤色LEDのVfが緑色LEDに比べて低いので、赤色LEDに電流が集中したという状態となっています。
実際にテスターでLED両端の電圧を測定したところ、赤色LEDは1.765V , 緑色LEDは1.766Vでした。
この電圧では赤色LEDは発光できるものの、緑色LEDは十分な電流が流れるほどの電圧に達していません。その結果、赤色LEDには電流が流れて点灯しますが、緑色LEDにはほとんど電流が流れず点灯しませんでした。
このように、LEDを異なる種類のまま単純に並列接続すると、わずかなVfの差によって電流の流れ方が大きく偏ることがあります。そのためLEDを並列接続する場合は、LEDごとに電流制限抵抗を設けるのが一般的です。
抵抗を追加する際にはGPIOの電流制限を考慮する必要があります。単純にこれまで使ってきた390Ωをひとつ追加して電流値を計算すると計算上では6mAを超える電流がGPIOに掛かってしまいます。したがって、総電流が4mA超えないよう680Ωの抵抗を2つ接続し、以下のような回路を組みました。
再度同じコードでデバッグを行ったところ、赤色LED、緑色LEDともに点灯しました。
LED両端の電圧を測定したところ、赤色LEDは1.750V , 緑色LEDは1.906Vでした。抵抗をそれぞれのLEDに追加したことで、各LEDに適切な電流が流れるようになりました。
以上、今回は各種ドキュメントの読み解き方、Config Toolsの使い方からLEDの動作原理にいたるまで組み込み開発初心者の目線から「困った」「詰まった」点を解説しました。NXPマイコンを使って初めてLチカにチャレンジするという方のご参考になれば幸いです。
=========================
本投稿の「Comment」欄にコメントをいただいても、現在返信に対応しておりません。
お手数をおかけしますが、お問い合わせの際には「NXPへの技術質問 - 問い合わせ方法 (日本語ブログ)」をご参照ください。
(既に弊社NXP代理店、もしくはNXPとお付き合いのある方は、直接担当者へご質問いただいてもかまいません。)
マイコンを使った開発において最も基本的なペリフェラルの一つであるGPIO(General Purpose Input/Output)をLEDの点滅を例に使い方を解説します。
GPIOは多くのマイコン開発者が最初に学ぶペリフェラルです。GPIOを使ってLEDを光らせてみたいけれど、「データシートの見方がわからない」「ピンの設定方法がわからない」という方も多いのではないでしょうか。本記事ではマイコン開発初心者向けに、FRDM-MCXA153を使ったGPIO入門を解説します。データシートや回路図からピン情報を読み解き、Pins Toolを使った設定を行いながら、最終的に外部LEDの制御を体験します。
(作業時間:15分) ※開発環境をインストール済みの前提