TechForum DigiKey Employee
作成者:Alex Aldag
最終更新者:Robert Nelson、2017年09月08日
このページは Atmel ATSAMD20 XPlained Pro ボードとその入門方法についてです。
入手可能なボード
ATSAMD20-XPRO(SAMD20 Xplained Pro)(DigiKey)
ATPROTO1-XPRO(Prototype extension board)(DigiKey)
ATIO1-XPRO(I/O extension board)(DigiKey)
ATOLED1-XPRO(128x32 OLED extension board)(DigiKey)
特徴とメリット
ARM Cortex-M0+コアを使用する SAM D20 は、Atmelがリリースした最新のフラッシュベースマイクロコントローラの1つです。D10、D11、D20、D21という4つの異なるデバイスファミリがあります。さらに、幅広い周辺機器セットと低消費電力プロセスとを組み合わせることにより、これらのAtme製品ラインはよりすばらしいものになります。
SAM D20 は、最高速度48MHzで動作します。これは、Atmelイベントシステム、シングルサイクル 32x32乗算器、2ステージパイプライン、シングルサイクル I/Oアクセスと結合されています。すべての部品にAtmel SERCOM(シリアル通信インターフェース)が搭載されており、I2C、SPI、USARTとして構成できる非常に柔軟なシリアルインターフェースです。各インターフェースは、多重化によって異なるI/Oピンに割り当てることができ、パーツの柔軟性を高めています。16ビット・タイマ/カウンタのインスタンスが複数あり、それぞれ周波数と波形の生成を実行するようにプログラムできます。アイドルおよびスタンバイの2つのスリープモードがあり、ソフトウェアで選択可能です。
ソフトウェア
Atmel Studio 6.2(最新バージョン) - 以前のバージョンのStudio 6.xを持っている場合、最新バージョンをインストールする前にそれらのバージョンをアンインストールすることをお勧めします。私は、バージョン6.1(ビルド 2562)からのアップグレードにおいて、Atmel Software Framework(ASF)が実質的にStudioから削除されているという問題を見つけました。私は前のバージョンに戻ってStudio 6.1(2562)、6.0、5.0を削除し(念のため)、フルバージョンの6.1(2674)をインストールしました。その結果、ASFのバージョン3.9.1がインストールされ、使用できるようになりました。
ハードウェア
AVR Xplainedキットに慣れ親しんでおられるのであれば、設計者(あなた)が様々なAtmelデバイスを容易に使い始められるように作成されたことはご存知でしょう。導入以来、主にATxmega、UC3、およびSAM4などの高性能製品向けの利用可能なボードの数が拡大しました。これらのボードでは、取り付けられたマイクロコントローラを使用してさまざまなセンサを実装する方法を示すアドオンボードがいくつも作成されています。現場やお客様からフィードバックを受けて、Atmelは、様々なGPIOや周辺機器へのアクセスをより簡単にする Xplained Pro ボードの発売を決定しました。もちろん、これを行う場合には、同じ周辺回路に接続できるボードがいくつか必要となります。そこでAtmelは、 Xplained Pro ボード(上記の「利用可能なボード」にリストされています)に適合するアドオンボードを開発しました。さらに容易に使用できるように、Atmelはこれらの新しいボードに SHA204 製品を組み込み、Atmel Studioがどのボードが接続されているかを識別できるようにしました。Atmel Studioは実際に、どのボードが接続されているか、どの拡張ボードが接続されているかをお知らせします。
SAMD20 Xplained Proの特長
- Atmel ATSAMD20J18 マイクロコントローラ
- 組み込みデバッガ(EDBG)
- USB インターフェース
- シリアルワイヤデバッグ(SWD)を介した SAM D20 ボード上のプログラミングとデバッグ
- シリアルワイヤデバッグ(SWD)を介した外部ターゲットのプログラミングとデバッグ
- デジタル I/O
- 2つの機械式ボタン(ユーザーボタンとリセットボタン)
- 1つのユーザーLED
- 3つの拡張ヘッダ
- 2種類の電源
- 外部電源
- 組み込みデバッガUSB
- 32kHz水晶振動子
プロジェクトの例
ここで紹介するすべての例は、Atmel Studio用に記述され、コンパイルされたものです。IARとKeilはこのチップとボードをサポートしているかどうかは分かりません。この記事を書いている時点で、サポートが利用可能であることを確認できていません。Atmel Software Framework内で現在利用可能なアプリケーションのリストが必要な場合は、Atmel SAMD20 Pro ASF にアクセスしてください。そこでは、サポートされているAtmelデバイスとボードのASFに関する更なる参照情報も見つけることができます。
LEDトグル
おそらく、最も基本的で、最もよく求められるプログラムは、LEDを点滅させることです。なぜですかって?まあ、ちょっと考えてみましょう。ボード上でLEDを点滅に切り替える時、実際には何が起こっているのでしょうか?まず、システムを初期化する必要があります。これは、時計がセットアップされ、動作していることを意味します。また、これは、LEDの電流をドライブ(駆動)またはシンク(吸い込み)できるようにGPIOピンが初期化されていること、場合によってはボタン入力があること、を意味します。また、割り込みを設定する必要があることも意味します。ボタンの押下からでも、タイマからでも起こる可能性があります。タイマを使う場合は(次の例に示すように)、タイマの初期化も必要です。基本的に、LEDを点滅させるためには、チップの最も重要な部分のいくつかを動作させる必要があります。それでは始めましょう。
幸運なことに、プレリリース版の SAMD20 Xplained Pro ボードとそれに使用できるソフトウェアを入手できました。前述したボードと明確な違いはないものの、どのピンがどこにいくかという点でいくつかの違いはありました。しかし、私たちの目的にとっては、それは何の違いにもなりません。コードにはいくつか違いがありましたが、それが大きな違いをもたらすほどではありませんでした。1つの違いは以下のコードブロックの中にあります。更新されたバージョンよりも、以下のバージョンの方が理解しやすいと思います。これまでにAtmel Studioを使用したことがない場合は、ヘルプメニューのヘルプに移動し(またはCTRL-F1キーを押す)、Atmel StuidoのファイルとAtmel Software Framework.fileに目を通すことをお勧めします。
そこで、Studio 6を使用して、Start PageからNew Example Projectを選択し、All Projectsから選択肢を変更して、Kitで並べ替えました。正しいバージョンのASFを選び、 SAM D20 Xplained Pro を見つけるまで下にスクロールして、LED Toggle Applicationを選びました。このプロジェクトの大部分は、SW0を押すとLED0が点灯するというものです。この時点で、「そんなことに何の意味があるんだ?配線することでも同じことができるじゃないか。」と思うかもしれません。しかし、ここで Atmel を使用すると、変更が少し簡単になるのです。この部分が何ができるかをいくつか示します。
メインファイル(led_toggle.c)の上部付近にいくつかの定義があります。これらの#defineステートメントを変更することで、ボタンを押したときにパーツがどのように反応するかを変更できます。PORTドライバ、EICドライバ、または、SysTickハンドラの使用、EICハンドラの使用、割り込みを使用するか割り込みを使用しないかなどによって反応を変更することができます。これにより、ピンの変化を見るさまざまな方法に使用するコードをデバッグする機能が提供されます。
/*
USE_INTERRUPTS USE_EIC Result
-------------- ------- ---------------------------------------------
false false Polled via PORT driver
false true Polled via EIC driver
true false Polled via PORT driver, using SysTick handler
true true Polled via EIC driver, using EIC handler
*/
#define USE_INTERRUPTS true
#define USE_EIC true
それでは、Atmelがこのプログラムを動作させるために取るステップを詳しく説明しましょう。最初のステップはシステムの初期化、system_init()です。この関数は次にsystem_clock_init()とsystem_board_init()関数を呼び出します。
#if CONF_CLOCK_XOSC_ENABLE == true
struct system_clock_source_xosc_config xosc_conf;
system_clock_source_xosc_get_default_config(&xosc_conf);
xosc_conf.external_clock = CONF_CLOCK_XOSC_EXTERNAL_CRYSTAL;
xosc_conf.startup_time = CONF_CLOCK_XOSC_STARTUP_TIME;
xosc_conf.auto_gain_control = CONF_CLOCK_XOSC_AUTO_GAIN_CONTROL;
xosc_conf.frequency = CONF_CLOCK_XOSC_EXTERNAL_FREQUENCY;
xosc_conf.on_demand = CONF_CLOCK_XOSC_ON_DEMAND;
xosc_conf.run_in_standby = CONF_CLOCK_XOSC_RUN_IN_STANDBY;
system_clock_source_xosc_set_config(&xosc_conf);
system_clock_source_enable(SYSTEM_CLOCK_SOURCE_XOSC);
#endif
system_board_init()関数は、使用するボードに完全に依存します。自作ボードを作る場合は、独自のboard_init関数を作る必要があります。この関数でAtmelが行ったのは、LED出力とボタン入力用のポートピンの設定だけでした。彼らのやり方は少し複雑に見えることを認めざるを得ませんが、Atmelのすべての開発ボードでうまく動作するようです。
void system_board_init(void)
{
struct port_config pin_conf;
port_get_config_defaults(&pin_conf);
/* Configure LEDs as outputs, turn them off */
pin_conf.direction = PORT_PIN_DIR_OUTPUT;
port_pin_set_config(LED_0_PIN, &pin_conf);
port_pin_set_output_level(LED_0_PIN, LED_0_INACTIVE);
/* Set buttons as inputs */
pin_conf.direction = PORT_PIN_DIR_INPUT;
pin_conf.input_pull = PORT_PIN_PULL_UP;
port_pin_set_config(BUTTON_0_PIN, &pin_conf);
}
この時点で、コードは一連の#if文に入り、ボタンが押されたときにどう反応するかを決定します。つまり、USE_INTERRUPTSとUSE_EICをどう設定するかによって、EICを使うか、割り込みを使うか、あるいはsystickを使うかが決まります。
#if USE_EIC == true
configure_extint();
#endif
#if USE_INTERRUPTS == true
# if USE_EIC == false
configure_systick_handler();
# else
configure_eic_callback();
# endif
system_interrupt_enable_global();
while (true) {
/* Do nothing - use interrupts */
}
#else
# if USE_EIC == false
while (true) {
update_led_state();
}
# else
while (true) {
if (extint_chan_is_detected(BUTTON_0_EIC_LINE)) {
extint_chan_clear_detected(BUTTON_0_EIC_LINE);
update_led_state();
}
}
# endif
#endif
もう一度、Atmel Studioを使用してNew Example Projectを選択すると、このプロジェクトがリストに表示されます。
遅延の例
皆が好んで「Blinky」と呼ぶものです。この例についても、前の例と同じことが当てはまります。これを動作させるには、チップの主要部を本当に動作させています。そこで、前と同じように、Studio 6.1に入り、新しいサンプルプロジェクトを作ることにしました。今回は、遅延動作の例 - SAM D20 Xplained Pro を選びました。説明を読むと、「システムクロックを初期化し、1Hzの一定周波数でLEDを点滅させる 」とあります。これはまさに「Blinky」そのものです。そして、ここでちょっとした問題にぶつかりました。どの例題プロジェクトでも、通常は目の前にMainというファイルがあることが期待されます。しかし、この場合はそうでもないのです。最終的に見ることになったのはこのファイルです。
このように、Mainを示す明らかなファイルがなかったので、ソリューションエクスプローラを通して探し回って見つけました。結局、ASF > common2 > services > delay > exampleという階層にあるdelay_example.cにたどり着いたのです。
LEDトグルと同じように、system_lock_init() 関数と system_board_init() 関数を呼び出す system_init() 関数があります。さて、これは「遅延の例」なので、遅延を得るために何かを設定する必要があります。この特定の例では、system_init() の完了後に delay_init() を呼び出しています。
この関数の最初の行は、実際には周波数を返す別の関数を呼び出しています。この場合、system_gclk_gen_get_hz(0)はチャンネル0のクロックコントロールレジスタを読み込み、クロック周波数をヘルツ単位で返します。次の2行は、それぞれ1ミリ秒と1マイクロ秒あたりのサイクル数を取得します。
この初期化の最後の行は、SysTick用のもので、コア内システムタイマのARM実装です。有効になると、これはロールオーバーした時にフラグを設定するかなり標準的なカウントダウンタイマとして働きます。この行で実行されていることは、使用しているクロックソースを読み込んで、SysTickを有効にするだけです。この場合、SysTick_CTRL_CLKSOURCE_Mskは1に設定されており、基準クロックではなくプロセッサクロックを使用していることを意味します。
void delay_init(void)
{
cycles_per_ms = system_gclk_gen_get_hz(0);
cycles_per_ms /= 1000;
cycles_per_us = cycles_per_ms / 1000;
SysTick->CTRL = SysTick_CTRL_CLKSOURCE_Msk | SysTick_CTRL_ENABLE_Msk;
}
そこで、次の一連の行はポートピンの設定をしています。ASFやコードのどこにも記載されていないのは、これがOLED1ボードで使用するために書かれたということです。以下に示すように、私が追加したのは、USER LED0も使用されるようにPA14を設定することです。LED1ボードをお持ちの場合は、LED0とLED2の両方が使われることになります。
つまり、ASF内では、ポートピンには既にデフォルトのセットアップがあって、内部プルアップが有効になっている入力として設定されています。最初の行では、pinというport_config構造体をセットアップします。次の行では、directionとinput_pullのデフォルト設定を取得し、pin構造体内に格納します。Portのピンやグループを変更するたびに、変更前にport_get_config_defaults()関数を呼び出す必要があります。これにより、ピンのセットアップが行われます。最後の行では、ピンのdirectionを入力から出力に変更しています。
port_pin_set_config()関数は、新しい設定(この場合は PA13とPA14)をそれぞれのポートピンに書き込みます。関数の注意書きには、ピンのdirectionが出力に設定されている場合、プルアップ/ダウン入力のコンフィギュレーションは無視されると述べています。しかし、実際にはそれは正確ではありません。その関数を確認したところ、内部プルアップは依然として有効であり、関数が呼び出されるとピンレジスタに書き戻されます。ところで、出力としては、プルアップが有効かどうかは実際にはあまり重要ではありません。出力レベルをHighに設定すると(出力レベルも)Highになり、出力レベルをLowに設定すると(出力レベルも)Lowになります。
一方、これらのパーツには、入力と出力の切り替えを容易にするために、いくつかの便利なレジスタが配置されています。各ポートにはDIRCLR、DIRSET、およびDIRTGLレジスタがあります。DIRCLRはPort Data Directionクリア、SETはセット、TGLはトグルです。したがって、CLEARのビットに1を書き込むと、DIRレジスタの対応するビットがクリアされ、そのピンが入力として構成されます。SETのビットに1を書き込むと、DIRレジスタの対応するビットがセットされ、そのピンは出力になります。そして、TOGGLEのビットに1を書き込むと、入力/出力と出力/入力の間で切り替わります。したがって、これらの特定のレジスタをいじり始めるときは、内部プルアップがまだ有効になっている可能性があることを念頭に置く必要があります。
コードに戻ると、最後の2行が行っているのは、ピンの出力をHighに設定することだけです。この関数は論理レベルを使用して出力を設定またはクリアします(true = 1、false = 0)。
struct port_config pin;
port_get_config_defaults(&pin);
pin.direction = PORT_PIN_DIR_OUTPUT;
port_pin_set_config(PIN_PA13, &pin);
port_pin_set_config(PIN_PA14, &pin);
port_pin_set_output_level(PIN_PA13, true);
port_pin_set_output_level(PIN_PA14, true);
さあ、これらの作業をすべて完了すると、ついにLEDを点滅させることができます。
LED0を点滅させるために、これらの関数にPA14も追加しました。つまり、for()ループ内でポートピンの出力レベルが切り替わります。これらのレジスタは、ポートピンの SET、CLEAR、またはTOGGLEに対する同じピンのdirectionレジスタと似ています。 この例では、関数はOUTTGLレジスタの対応するビットに1を書き込み、そのピンを切り替えます。
ご覧のとおり、それぞれのfor()ループには、delay_s()、delay_ms()、およびdelay_cycles()という独自の遅延関数があります。関数名は一目瞭然で、delay_s()は何秒遅らせるといった具合です。しかし、ここは複雑になりすぎているように思います。まず、delay_s(delay)をcpu_delay_s(delay)と定義していますが、これはdelay_cycles_ms(1000 * delay)と定義されています。この関数はwhile()ループであり、delay_cycles(cycles_per_ms)という関数でカウントダウンします。
そこで、cycle_counter.hファイルの中でこの関数を見つけました。これは静的なインラインのvoid関数で、SysTickカウンタをセットアップし、それがダウンするのを待ちます。興味深いのは、delay_s、delay_ms、delay_us(ここでは使われていない)はすべてdelay_cycles()関数に移っていくことです。もちろん、delay_msとdelay_usはcpu_delay_msとcpu_delay_usとして定義され、これらはそれぞれdelay_cycles_msとdelay_cycles_usとして定義されています。これらはもちろん、SysTick用の同じ静的インライン関数を呼び出すことになります。上述したことを思い起こすと、cycles_per_msはシステムクロック(ヘルツ)を1000で割った値に等しくなります。delay_cycles_ms()関数は、この値を使って何サイクル遅延させるかを決定するためにdelay_cycles()関数を呼び出します。同様に、delay_cycles_us()は、上に示されているcycles_per_usの値を使用して、delay_cycles()関数が待機するサイクル数を決定します。
つまり、このwhile()ループの設定方法だと、そのまま実行しても最後のループには到達しません。最初の2つのうち1つをコメントアウトすれば、最後のループが実行されます。100クロックサイクルのdelayが5000カウントだけですので、両方がオンになっていることに気づくことはないでしょう。しかし、もし50000カウントまで上げれば、より見やすくなります。
while (true) {
for (int i = 0; i < 5; i++) {
port_pin_toggle_output_level(PIN_PA13);
port_pin_toggle_output_level(PIN_PA14);
delay_s(1);
}
for (int i = 0; i < 50; i++) {
port_pin_toggle_output_level(PIN_PA13);
port_pin_toggle_output_level(PIN_PA14);
delay_ms(100);
}
for (int i = 0; i < 5000; i++) {
port_pin_toggle_output_level(PIN_PA13);
port_pin_toggle_output_level(PIN_PA14);
delay_cycles(100);
}
}
そこで、そのままのコードでは最後の関数に到達できないという事実に対処するために、少し手を加えてみました。3つのfor()ループすべてに到達できるように、iをmain()内のvolatile 変数にしました。また、PA14(LED0)の初期出力レベルを変更し、PA13(LED2)がオンのときにオフになるようにすることにしました。これにより、2つのLEDは交互に点灯します。
int main(void)
{
system_init();
delay_init();
volatile int i;
struct port_config pin;
port_get_config_defaults(&pin);
pin.direction = PORT_PIN_DIR_OUTPUT;
port_pin_set_config(PIN_PA13, &pin);
port_pin_set_config(PIN_PA14, &pin);
port_pin_set_output_level(PIN_PA13, true);
port_pin_set_output_level(PIN_PA14, false);
while (true) {
for (i = 0; i < 5; i++) {
port_pin_toggle_output_level(PIN_PA13);
port_pin_toggle_output_level(PIN_PA14);
delay_s(1);
}
for (i = 0; i < 50; i++) {
port_pin_toggle_output_level(PIN_PA13);
port_pin_toggle_output_level(PIN_PA14);
delay_ms(100);
}
for (i = 0; i < 50000; i++) {
port_pin_toggle_output_level(PIN_PA13);
port_pin_toggle_output_level(PIN_PA14);
delay_cycles(100);
}
}
}
まとめ
この2つのサンプルプロジェクトは、入手できる中でも最も基本的なものです。最初のサンプルプロジェクトは、ボタンを押すとLEDが点灯します。2つ目のサンプルプロジェクトは、タイマを使ってLEDを点滅させるものです。ASF内にはさらに多くのプロジェクトが掲載されていますし、ATSAMD20 Xplained Pro ボードや拡張ボードを扱ったページがさらに増えていくことでしょう。
著者の注記
このページは、DigiKeyアプリケーションエンジニアリンググループによって開設され、管理されています。このページは、エンジニア、愛好家(ホビイスト)、起業家、その他の技術志向の方々をサポートするためにDigiKeyが提供している数多くあるサポートの1つです。私たちは、これらのページのコンテンツを拡大し、更新するよう努めていきますが、何らかの形でお客様のお役に立てたときには是非お知らせください。お客様からのフィードバックが仕事の糧となり、eewikiに取り組んでいくことができます。コメントや質問があれば投稿いただくか、以下のリンクから送信してください。著者への具体的な要望がある場合は、件名に著者の名前を入れてください。今後、ATSAMD20 のボードやチップに関するコンテンツを増やしていく予定です。
コメント/質問
このページまたは他のページの情報に関するご質問やご意見は、TechForumにアクセスしてください:TechForum