SSブログ

PSoC Creator で FM0+ の Lチカ (4) [FMx]このエントリーを含むはてなブックマーク#

FM0+ 評価ボード

前回まで、ソフトウェアループ、 PWM、タイマ割り込みを使って「Lチカ」を行ってきました。 今回は、 Direct Memory Access (DMA) を使って、「Lチカ」してみます。

使用するボードは、 FM0+ S6E1C-Series Starter Kit (FM0-64L-S6E1C3) です。

回路図に GPIO と RT と DSTC を配置する

GPIO と RT と DSTC を配置する

プロジェクトを作成するところまでは、前回までと同じです。 今回は、GPIO コンポーネントと Reload Timer (RT) コンポーネントに加えて Descriptor System data Transfer Controller (DSTC) コンポーネントを配置します。 この記事では、 DMA を使うと言いましたが、この MCU には DMA というブロックがありません。 「CPU を煩わせずにデータの転送を行う機能」として DSTC というブロックが DMA の代わりに搭載されています。 このブロックは、ディスクリプタベースのデータ転送機能を持っており、 DMA よりはるかに高機能で複雑な動作をさせることが出来ます。

このシステムでは、 RT でタイミング信号を発生し、このタイミング信号で DSTC にトリガをかけ、 GPIO の出力値を更新します。 出力するデータにトグルパターンを使用する事で、タイミング信号の周期で「Lチカ」が出来ます。

DSTC は "Component Catalog" の "System" から回路図に Drag&Drop します。 インスタンスの名前は、 "DSTC" としました。

コンポーネントの設定

RT の Interrupt タブ

まず、 RT コンポーネントを設定します。 この MCU では、 RT が発生した割り込み信号をタイミング信号として使用します。 そのため、割り込みを発生させるための設定を行わなくてはなりません。

「Interrupt タブ」で、 "bRtUnderflowIrq" を "true" に設定して、周期的な割り込み信号を発生させます。 ただし、コールバック関数を呼び出す必要はありません。 このような場合、 "pfnRtUnderflowIrqCb" を削除して空欄にしておくと関数の作成を省略できます。

"bTouchNvic" は "false" に設定します。 発生した信号を Nested Vector Interrupt Controller (NVIC) に渡す必要はありません。 以上で、タイミング信号が発生できます。


RT の RT タブ

「RT タブ」での変更点は、周期割り込みを使う場合と同じです。 "enRtPres" で RT のクロックに使用されるプリスケーラの分周比を "1/2048" に設定します。


DSTC の Basic タブ

DSTC コンポーネントはデフォルトのまま使用します。

これで回路図の設定は終わりです。

端子を割り当てる

端子の設定

次は、端子の割り当てを行います。 "Pin_Red" に "P3D" を設定します。

以上でハードウェアの設定は終わりです。 プログラムを記述する前に "Build" して、あらかじめ API を作成しておきます。

RT の初期設定

RTの初期設定

ソースコードのうち、 RT コンポーネントの初期設定は、以下のようになっています。

#include "project.h"

#define     CYCLE           (8000000/2048/2)    // 0.5秒を作る分周比

// RTコンポーネントの初期化処理
void RtInit(void) {
    Bt_Rt_Init(&RT_HW, &RT_Config);         // 初期化
    Bt_Rt_WriteCycleVal(&RT_HW, CYCLE);     // 割り込み周期
    Bt_Rt_EnableCount(&RT_HW);              // カウンタを起動
}

周期割り込みを使った時と同じように、0.5秒ごとに割り込み信号を発生させます。 この初期化関数では、カウンタを起動する所まで実行しますが、トリガはかけていません。 RT と DSTC 両方のコンポーネントの準備が出来てから、トリガをかけます。

DSTC の初期設定

DSTCの初期設定

DSTC の初期設定は、かなり複雑です。

// GPIOに出力するパターンデータ
uint32_t gpio_data[2] = {0xFFFFFFFF, 0x00000000};

gpio_data[] には、 GPIO の出力レジスタに代入する値が格納されています。 RT からタイミング信号を受け取るたびに、これらの値を一つずつ出力レジスタに入れる事により、 LED を点滅させます。 この配列には、ふたつの要素のみ定義されていますが、繰り返し機能を使う事によって、二番目の出力の後、一番目の出力に戻り、無限に LED を点滅させることが出来ます。

// DSTCのディスクリプタは、永続した記憶域に配置する
stc_dstc_des01234_t descriptor;     // DSTC descriptor

DSTC の制御に使われるデータは、ディスクリプタと呼ばれるメモリ領域に配置されます。 ここでは、 descriptor という変数をディスクリプタ領域として使用します。

DSTC のディスクリプタは、その内容によって可変長です。 ここで使用されているディスクリプタは、4ワードのディスクリプタです。

// DSTCコンポーネントの初期化処理
void DstcInit(void) {
    // 初期設定構造体の作成
    stc_dstc_config_t dstc_config = {
        0,                          // ディスクリプタの先頭は、後で設定する
        DSTC_Config                 // コンポーネントで設定されたパラメータ
    };

DstcInit() 関数の冒頭で、 dstc_config 構造体を宣言しています。 DSTC コンポーネントは、この構造体を初期化関数に渡すことで初期化します。

構造体の最初の要素には、ディスクリプタの先頭ポインタを入れます。 これは、後で設定します。 それ以降の要素は、コンポーネントの設定ダイアログで設定した内容を DSTC_Config というマクロで渡します。 このマクロは、複数の要素を並べた内容になっており、事実上、設定構造体の初期設定でしか使用する事ができません。 不自由なのですが、完結したライブラリの仕様ですので従いましょう。

    
    // ディスクリプタの設定
    PDL_ZERO_STRUCT(descriptor);
    descriptor.DES0.DV    = 3u;     // 転送終了後もDSTCが継続して権限を持つ
    descriptor.DES0.MODE  = 1u;     // リクエストごとに1ワード転送する
    descriptor.DES0.ORL   = 1u;     // 転送終了後カウンタパラメータを再設定する
    descriptor.DES0.TW    = 2u;     // 32-bitワード
    descriptor.DES0.SAC   = 1u;     // 転送元アドレスを1ワードずつインクリメントしてINNERで再設定する
    descriptor.DES0.DAC   = 5u;     // 転送先アドレスは固定する
    descriptor.DES0.CHRS  = 0u;     // ディスクリプタチェーンは使わない
    descriptor.DES0.DMSET = 0u;     // 転送終了後も転送信号を受け付ける
    descriptor.DES0.CHLK  = 0u;     // ディスクリプタチェーンは使わない
    descriptor.DES0.ACK   = 1u;     // データ転送後にACKを返す
    // DES0フィールドのチェックサムを計算する
    descriptor.DES0.PCHK  = DSTC_PCHK_CALC(descriptor.u32DES0);

    // 転送カウンタの設定
    descriptor.DES1_mode1.IIN = 2u; // 2ワード転送する
    descriptor.DES1_mode1.IRM = 2u; // 2ワード残っている
    descriptor.DES1_mode1.ORM = 1u; // INNER転送を1回実行する

    // 転送元・転送先アドレス
    descriptor.DES2 = (uint32_t)gpio_data;          // 出力パターンデータ
    descriptor.DES3 = (uint32_t)&FM_GPIO_PDOR3;     // GPIOの出力データレジスタ

    // 転送終了後に再設定されるカウンタ値
    descriptor.DES4_mode1 = descriptor.DES1_mode1;  // DES1のカウンタ値をコピーする

DSTC の転送単位は、 8bit, 16bit, 32bit から選びます。 転送単位を示すのが、 DES0.TW フィールドです。 今回は、 GPIO の出力レジスタに 32bit で書き込みを行います。

DSTC では、一つのディスクリプタで繰り返し転送を行う事が出来ます。 この繰り返しを行うためのループ二重になっており、それぞれのループを INNER (内側)と OUTER (外側)と呼んでいます。 INNER の繰り返し回数と OUTER の繰り返し回数を掛け合わせたものが、ディスクリプタの転送回数になります。 INNER カウンタの初期値と繰り返し回数を表すのが、 DES1_mode1.IIN と DES1_mode1.IRM です。 また、 OUTER カウンタの初期値は DES1_mode1.ORM です。

DSTC のディスクリプタには、 MODE0 と MODE1 の二種類があります。 モードを指定するのが、 DES0.MODE フィールドです。 MODE0 は、 INNER の繰り返しをまとめて実行します。 一方、 MODE1 は、 INNER の転送を1転送単位ずつ実行します。 今回は、 MODE1 を使い、1転送ずつ GPIO 出力を変更して LED の点滅を表現します。

転送元のデータは、 gpio_data[] 配列に入っており、 DES2 でアドレスを指定します。 また、転送先は P3 ポートの出力レジスタである FM_GPIO_PDOR3 を DES3 で指定します。 これらの転送元アドレスは、1転送ごとにアドレスをインクリメントして配列中の次の値を使用します。 また、アドレスは、 INNER の繰り返し回数のあと、元のアドレスに再設定されます。 このアドレスの振る舞いを指定しているのが、 DES0.SAC です。 一方、転送先アドレスは、出力レジスタに固定されたままです。 この振る舞いを指定しているのが、 DES0.DAC です。

ここで、転送先に FM_GPIO_PDOR3 を指定していますが、そもそも Build しないと GPIO コンポーネントが本当に P3 に割り当てられたかはわかりません。 本来であれば、 GPIO コンポーネントに配置された出力レジスタのアドレスが定義されれば良いのですが、そうなってはいません。 ぜひ、マクロを加えてほしい所です。

OUTER ループが既定の繰り返し回数に達したら、転送が終了します。 このとき、 DES1_mode1, DES2, DES3 のそれぞれの値を再設定する機能があります。 この機能を働かせるか否かを決めるのが DES0.ORL フィールドです。 今回の設定では、 DES1_mode1 の繰り返しカウンタだけを再設定しています。 再設定値は DES4_mode1 に設定しますが、 DES1_mode1 と同じ内容ですので、そのままコピーしています。

今回の使い方では、転送が終了しても続けて転送を行いたいので、終了後も転送を継続するための設定が必要です。 この設定を行っているのが、 DES0.DV です。 デフォルトの 0 にすると、転送終了後のディスクリプタのアクセス権限を CPU が持つのですが、 3 にすると継続して DSTC がアクセス権限を保持し、転送リクエストを待ち続けます。

DES0.PCHK には、 DES0 のチェックサムが入ります。 このチェックサムが合わないと、ディスクリプタは無効になります。 チェックサムは DSTC_PCHK_CALC マクロで計算させます。

    
    // ディスクリプタの先頭アドレス
    dstc_config.u32Destp = (uint32_t)&descriptor;
    
    // 設定構造体でDSTCを設定する
    Dstc_Init(&dstc_config);
}

最後に設定構造体にディスクリプタのアドレスを設定し、 DSTC を初期化します。 これで、 DSTC の設定ができました。

main() 関数の記述

main()関数

初期化ルーチンが揃ったら、 main() 関数を記述します。

int main(void) {
    /* Place your initialization/startup code here (e.g. MyInst_Start()) */
    // コンポーネントの初期設定
    Pin_Red_GpioInitOut(1u);
    RtInit();
    DstcInit();
    
    // DSTCの制御
    Dstc_SetCommand(CmdErclr);                      // DSTCのエラーをクリア
    Dstc_SetCommand(CmdRbclr);                      // 何かをクリア
    Dstc_SetHwdesp(DSTC_IRQ_NUMBER_BT0_IRQ0, 0u);   // RTのIRQ0で0番目のDESを起動する
    Dstc_SetDreqenbBit(DSTC_IRQ_NUMBER_BT0_IRQ0);   // RTのIRQ0信号をDSTCに引き込む

    // RTの制御
    Bt_Rt_EnableSwTrig(&RT_HW);                     // RTの起動

    for (;;) {
        /* Place your application code here. */
    }
}

まず、三つのコンポーネントの初期化を行います。 GPIO の初期化は Pin_Red_GpioInitOut() 関数で、 RT と DSTC の初期化は、それぞれの初期化関数で行います。

続いて、 DSTC を起動します。 Dstc_SetCommand() 関数で、あらかじめフラグをクリアしておきます。 そして、 Dstc_SetHwdesp() 関数で割り込み信号がきたら、ディスクリプタのどの部分を実行すれば良いかを指定します。 今回の場合には、 Base Timer #0 (BT0) の IRQ0 がきたら、0番目のディスクリプタを実行します。

ここで、割り込み信号をインデックス DSTC_IRQ_NUMBER_BT0_IRQ0 で表現していますが、 RT コンポーネントが BT0 に割り当てられるのかどうかは、 Build してみなくてはわかりません。 にもかかわらず、このような表記になっているのは、 RT コンポーネントから特定の BT を指し示す方法が無いからです。 ぜひ、 PSoC Creator が生成するファイルにマクロを用意してほしい所です。

最後に Dstc_SetDreqenbBit() 関数で割り込み信号を CPU の代わりに DSTC に接続します。 これで、割り込み信号により DSTC が動作を始めるようになります。

最後のステップは、 RT の起動です。 すでに、割り込み信号が DSTC に接続されていますので、 Bt_Rt_EnableSwTrig() 関数で RT にトリガをかけると、周期的に DSTC に対して転送要求を行います。

初期設定のあと、プログラムは無限ループに入ります。 割り込み要求は発生しないので、 CPU は割り込みを受けることも無くループを回り続けます。 これで、ソースコードは終わりです。 "Build" して、 "Program" すると、 LED が点滅を始めます。 「Lチカ」できました。


PSoC Creator で FM0+ の Lチカ (3) [FMx]このエントリーを含むはてなブックマーク#

FM0+ 評価ボード

前回の記事では、精密な「Lチカ」を行うために PWM を使って LED を直接駆動していました。 今回は、周期割り込みを使って、「Lチカ」してみます。

使用するボードは、 FM0+ S6E1C-Series Starter Kit (FM0-64L-S6E1C3) です。

回路図に GPIO と RT を配置する

GPIO と RT を配置する

プロジェクトを作成するところまでは、前回までと同じです。 今回は、 GPIO コンポーネントと Reload Timer (RT) コンポーネントを配置します。 GPIO は "Component Catalog" の "Ports and Pins" から回路図に Drag&Drop します。 また、 Reload Timer は "Component Catalog" の "Digital" から Drag&Drop します。 GPIO は、名前を "Pin_Red" に変更しておきます。


Interrupt タブ

RT コンポーネントは、ダウンカウンタで構成されたタイマで、カウンタがゼロになったらあらかじめ設定された値をカウンタに書き込みます。 書き込みイベントが周期的に発生するため、周期割り込みを発生するのに使用されます。

このコンポーネントは、割り込みの機能だけを使い、入出力は使いません。 そのため、「Basic タブ」 は変更しません。

「Interrupt タブ」では、どのような種類の割り込みを発生させ、その時にどの関数を呼び出すかを設定します。 "bRtUnderflowIrq" を "true" に設定すると、 Reload Timer の一周期ごとに割り込みが発生します。 その時に "pfnRtUnderflowIrqCb" に設定されたコールバック関数が呼び出されます。 ここでは、 "UnderflowCb" としました。 実際には、この名前の初めにコンポーネントの名前を付けた "RT_UnderflowCb()" が呼び出されます。

"bTouchNvic" も "true" に設定します。 このパラメータを "true" にすると、割り込み受付モジュール Nested Vector Interrupt Controller (NVIC) の設定が一緒に行われます。 以上で、周期割り込みを受け付けてコールバック関数を呼び出すようになります。 フラグをクリアするなどの操作は、自動的に生成されるので、ユーザが気にする必要はありません。


RT タブ

「RT タブ」では、一項目を設定します。 "enRtPres" で RT のクロックに使用されるプリスケーラの分周比を設定します。 PWM コンポーネントの "enPwmPres" と考え方は同じです。 今回も、最大分周比である "1/2048" を使用します。 デフォルト状態でのクロック周波数は 8MHz なので、 RT の駆動クロックは、約4kHzとなります。

これで回路図の設定は終わりです。

端子を割り当てる

端子の設定

次は、端子の割り当てを行います。 "Pin_Red" に "P3D" を設定します。

以上でハードウェアの設定は終わりです。 プログラムを記述する前に "Build" して、あらかじめ API を作成しておきます。

ソースコードの記述

ソースコード

次は、ソースコードの記述です。

#include "project.h"

#define     CYCLE       (8000000/2048/2)    // 0.5秒を作る分周比

void RT_UnderflowCb(void) {
    Pin_Red_GpioPut(!Pin_Red_GpioGet());    // GPIO 出力を反転する
}

int main(void) {
    /* Place your initialization/startup code here (e.g. MyInst_Start()) */
    Pin_Red_GpioInitOut(1);                 // GPIO を出力に設定する
    Bt_Rt_Init(&RT_HW, &RT_Config);         // RT の初期設定
    Bt_Rt_WriteCycleVal(&RT_HW, CYCLE);     // RT 周期
    Bt_Rt_EnableCount(&RT_HW);              // RT を起動する
    Bt_Rt_EnableSwTrig(&RT_HW);             // RT にトリガをかける

    for (;;) {
        /* Place your application code here. */
    }
}

必要なのは、割り込みコールバック関数と初期設定だけです。 割り込みコールバック関数 "RT_UnderflowCb()" は、 RT のカウンタがゼロになるたびに呼び出される関数です。 この関数では、 GPIO "Pin_Red" の出力を反転させています。 周期割り込みが0.5秒ごとに発生するので、 LED は、 1Hz で点滅します。

GPIO コンポーネントは、 "main()" 関数内で "GpioInitOut" メソッドにより出力に設定します。 出力の初期設定値は、 "1" です。

"Bt_Rt_Init()" は RT の初期設定を行う関数です。 PWM の時と同じように第一引数に &RT_HW を渡して、設定すべきタイマブロックを指定しています。 第二引数の &RT_Config には、コンポーネントの設定ダイアログで設定したパラメータが格納されています。

"Bt_Rt_WriteCycleVal()" は、 RT の周期を設定します。 周期の単位は、設定ダイアログで指定した約4kHzの RT 駆動クロックです。 このプログラムでは、コンパイル時に設定値 (CYCLE) を計算させて、周期に0.5秒を設定しています。

"Bt_Rt_EnableCount()" で、 RT の動作を開始します。 ただし、この時には RT カウンタは動き出しません。 カウンタが動きだすのは、 "Bt_Rt_EnableSwTrig()" でトリガをかけた時です。 トリガを受けた RT は、継続して割り込みをさせます。

ここで使用されている関数群は、 Peripheral Driver Library (PDL) ライブラリそのものです。 このライブラリの設計思想は、従来の PSoC の API とは異なっているので、注意が必要です。

ソースコードは、以上です。 "Build" して、 "Program" すると、 LED が点滅を始めます。 「Lチカ」できました。


PSoC Creator で FM0+ の Lチカ (2) [FMx]このエントリーを含むはてなブックマーク#

FM0+ 評価ボード

前回の記事では、時間稼ぎループをソフトウェアで実現していたために、精密な「Lチカ」にはなりませんでした。 今回は、ハードウェアの力を借りて、「Lチカ」してみます。

使用するボードは、 FM0+ S6E1C-Series Starter Kit (FM0-64L-S6E1C3) です。

回路図に PWM を配置する

PWM を配置

プロジェクトを作成するところまでは、前回と同じです。 今回は、 PWM コンポーネントを配置します。 "Component Catalog" の "Digital" にある "PWM" を Drag&Drop で回路図に配置します。


Basic タブ

次にコンポーネントの設定を行います。 このプロジェクトでは、 PWM 出力を直接赤い LED に接続します。 その際に PWM 出力で使用される端子を Timer I/O A (TIOA) と呼びます。 Basic タブでは、"ConnectTIOA" を "true" に設定して TIOA 出力を有効にします。


PWM タブ

PWM タブでは、二項目を設定します。 まず、 "enPwmOutputPolarity" で出力の位相を設定します。 "Initially high" に設定すると、初期状態が HIGH になります。 TIOA に接続される LED は、電源とポート出力の間に接続されています。 そのため、負論理 (Active Low) 出力に設定します。

"enPwmPres" は、 PWM のクロックに使用されるプリスケーラの分周比を設定します。 今回は、クロックに比べて遅い点滅にするため、最大分周比である "1/2048" を使用します。 デフォルト状態でのクロック周波数は 8MHz なので、 PWM の駆動クロックは、約4kHzとなります。

これで回路図の設定は終わりです。 端子を表すコンポーネントがありませんが、設定で有効にした TIOA が使われることになります。

端子を割り当てる

端子の設定

次は、端子の割り当てを行います。 ここでは、 PWM の TIOA 端子をどこに割り当てるかを指定します。 割り当てるのは、赤い LED が接続されている P3D 端子です。 "PWM:TIOA" に "P3D" を設定します。

以上でハードウェアの設定を終わりです。 プログラムを記述する前に "Build" して、あらかじめ API を作成しておきます。

ソースコードの記述

ソースコード

次は、ソースコードの記述です。

#include "project.h"

#define     CYCLE       (8000000/2048/2)    // 0.5秒を作る分周比

int main(void) {
    /* Place your initialization/startup code here (e.g. MyInst_Start()) */
    PWM_SetPinFunc_TIOA_OUT();                  // PWM の出力機能を有効にする
    Bt_Pwm_Init(&PWM_HW, &PWM_Config);          // PWM の初期設定
    Bt_Pwm_WriteCycleVal(&PWM_HW, CYCLE - 1);   // PWM 周期
    Bt_Pwm_WriteDutyVal(&PWM_HW, CYCLE / 2);    // PWM デューティー
    Bt_Pwm_EnableCount(&PWM_HW);                // PWM を起動する
    Bt_Pwm_EnableSwTrig(&PWM_HW);               // PWM にトリガをかける

    for (;;) {
        /* Place your application code here. */
    }
}

必要なのは、初期設定だけです。 まず、 "PWM_SetPinFunc_TIOA_OUT()" で PWM の TIOA に割り当てられた端子、すなわち P3D 端子を出力に設定します。 この関数は、 PWM コンポーネントのメソッドのように記述されています。

ところが、これ以降の関数ではメソッドという扱いにはなっていません。 次の "Bt_Pwm_Init()" は PWM の初期設定を行う関数ですが、引数としてタイマのレジスタアドレスである &PWM_HW を渡して、設定すべきタイマブロックを指定しています。 このレジスタアドレスを使って、各種レジスタを関数で設定するという仕組みです。 第二引数の &PWM_Config には、 PSoC Creator の設定ダイアログで設定したパラメータが格納されています。 設定ダイアログを見てわかるように、このパラメータには PWM の周期やデューティーといった情報は含まれてはいません。 これらの情報は、別途設定をすることになります。

"Bt_Pwm_WriteCycleVal()" と "Bt_Pwm_WriteDutyVal()" は、 PWM の周期とデューティーを設定します。 ここでも引数にレジスタアドレスを渡しています。 周期とデューティーの単位は、設定ダイアログで指定した約4kHzの PWM 駆動クロックです。 このプログラムでは、コンパイル時に設定値を計算させて、周期に0.5秒、デューティーにその半分 (50%) を設定しています。

"Bt_Pwm_EnableCount()" で、 PWM の動作を開始します。 ただし、この時には PWM カウンタは動き出しません。 カウンタが動きだすのは、 "Bt_Pwm_EnableSwTrig()" でトリガをかけた時です。 トリガを受けた PWM は、継続して LED を点滅させます。

ここで使用されている関数群は、 Peripheral Driver Library (PDL) ライブラリそのものです。 このライブラリの設計思想は、従来の PSoC の API とは異なっているので、注意が必要です。

ソースコードは、以上です。 "Build" して、 "Program" すると、 LED が点滅を始めます。 「Lチカ」できました。


PSoC Creator で FM0+ の Lチカ (1) [FMx]このエントリーを含むはてなブックマーク#

FM0+ 評価ボード

PSoC Creator が、 Revision 4.0 から FM0+ MCU にも対応するようになりました。 評価ボードも入手できるので、さっそく「Lチカ」してみましょう。

使用するボードは、 FM0+ S6E1C-Series Starter Kit (FM0-64L-S6E1C3) です。

プロジェクトを作成する

ターゲット選択

プロジェクトの作成手順は、これまで PSoC のプロジェクトを作成した時と同じです。 まず、メニューから "File" → "New" → "Project..." を選んでダイアログを開きます。

ダイアログの最初の画面では、デバイスを選択します。 最近の PSoC Creator では、デバイスの型番を指定する代わりに、キットの型番を選択していましたが、 FM0+ のキットはリストに並んでいません。 そこで、 "Target Device" を選択しデバイスリストから "S6E1C32D0AGV20000" を選びます。


初期プロジェクト選択

次にプロジェクトの初期状態を選択します。 今回は、白紙の状態からプロジェクトを作成しますので、 "Empty Schematic" を選択します。


ディレクトリと名前の設定

最後に、プロジェクトを配置するディレクトリと Workspace 名および Project 名を選択します。 これで、プロジェクトが作成できました。

回路図に GPIO を配置する

GPIO コンポーネント

次は、回路図に GPIO コンポーネントを配置します。 "Project Explorer" から ".cysch" ファイルの回路図を開きます。 そして、 "Component Catalog" の "Ports and Pins" にある "GPIO" を Drag&Drop で回路図に配置します。


GPIOを配置

配置されたコンポーネントをダブルクリックして、設定ダイアログを開きます。


GPIOの設定ダイアログ

設定項目は、わずかです。 入出力の設定さえありません。 ここでは、コンポーネントの名前を "Pin_Red" に変更します。 これで、回路図の準備は終わりです。

端子を割り当てる

端子設定を呼び出す

回路図が出来たら、端子の割り当てを行います。 PSoC Creator 4.0 からは、 "Workspace Explorer" から直接端子設定画面を呼び出せるようになっています。 "Design Wide Resources" の下にある "Pins" を開きます。


端子の設定

端子の設定方法は、これまでと同じです。 この評価ボードでは、赤い LED が、 P3D 端子に接続されています。 "Pin_Red:GPIO" に "P3D" を設定します。

以上でハードウェアの設定を終わりです。 プログラムを記述する前に "Build" して、あらかじめ API を作成しておきます。

ソースコードの記述

ソースコード

次は、ソースコードの記述です。 PSoC 比べると、記述は多めです。

int main(void) {
    /* Place your initialization/startup code here (e.g. MyInst_Start()) */
    Pin_Red_GpioInitOut(1);  // GPIO を出力に設定する

    for (;;) {
        /* Place your application code here. */
        uint32_t i;
        for (i = 0; i < 1000000; i++) ;  // ちょっと待つ
        Pin_Red_GpioPut(!Pin_Red_GpioGet());  // GPIO 出力を反転する
    }
}

GPIO コンポーネントでは、入出力の方向さえ定めていませんでした。 そのため、 GPIO を出力として設定する必要があります。 "GpioInitOut" メソッドで設定を行います。 引数には、出力の初期設定値が入ります。

PSoC では、待ち時間を作るための CyDelay() などの関数がありましたが、 FM0+ の場合には見つかりませんでした。 そこで、目分量で1000000回のループを作成し、待ち時間を作っています。 デフォルトの状態では、内部 8MHz クロックをそのまま CPU で使用していますので、これで1秒近辺の待ち時間が出来るでしょう。

GPIO の読み出しと書き込みには、メソッド "GpioGet" と "GpioPut" を使用します。 ここでは、読み出した値を論理反転して書き込み、 LED を点滅させます。

ここで使用されているメッソド群は、間接的に Peripheral Driver Library (PDL) と呼ばれるライブラリを呼び出しています。 どんな事ができるのかを知るためには、 PDL も知る必要がありそうです。

ソースコードは、以上です。 "Build" して、 HEX ファイルを作成します。

MCUに書き込む

CMSIS-DAPの検出

PSoC の場合、 MiniProgKitProg などの PSoC 固有のインターフェイスが使用されていました。 評価ボードの場合、標準的なインターフェイスは CMSIS-DAP です。

メニューから "Debug" → "Select Debug Target..." を選ぶとデバッガのインターフェイスが表示されます。 評価ボードを接続すると、 "CMSIS-DAP" が認識されます。 問題なくデバッガとして認識されるようです。

プログラムは、メニューの "Debug" → "Program" で書き込まれます。 書き込みが終わると、そのままプログラムが実行されて、 LED が点滅します。 「Lチカ」できました。


この広告は前回の更新から一定期間経過したブログに表示されています。更新すると自動で解除されます。