PSoC 6 のデュアルコアでLチカ (5)


これは、PSoC Advent Calendar 2017の8日目に突っ込まれた記事です。

前回までのあらすじ

これまでの記事では、ソフトウェアによりタイミングを生成してLチカを実現しました。
今回は、ハードウェアタイマを使用して、より正確なLチカを行います。もちろん、デュアルコアですよ。

本プロジェクトのコンセプト

今回のプロジェクトではハードウェアタイマを一つ使います。

タイマと言っても、実体はPWMです。Clockコンポーネントの分周比が上げられないため直接低周波数の信号を出せないという理由でTCPWMモジュールが使われています。TCPWMは、32個も入っているのでケチケチせずに使ってしまいましょう。

PWM信号の立ち上がり・立ち下がりのタイミングから割り込み信号を生成し、それぞれを点灯・消灯のタイミングとしています。Int_Clear割り込みが点灯に使われ、Int_Set割り込みが消灯に使われます。

このプロジェクトでは、Int_Clear割り込みがCortex-M0+に割り込みをかけ、Int_Set割り込みがCortex-M4に割り込みをかけます。このように二つのCPUのどちらに割り込み信号を渡すかを決めるため、PSoC Creator.cydwrファイルのInterruptsタブを設定します。このプロジェクトでは、以下のように設定しています。

Int_Set割り込みは、PSoC 6システムの123番割り込みに割り当てられて、そのままCortex-M4の123番割り込みに供給されます。

一方、Int_Clear割り込みは、PSoC 6システム内の122番割り込みに割り当てられ、Cortex-M0+の8番割り込みとして供給されています。このように割り込み番号の付け替えが行われるのは、Cortex-M0+が受け付けることのできる割り込み要因数が限られているため、交換機を介して割り込み受付ブロックに導いているためです。

Cortex-M0+の割り込みのうち、0から7までは、Deep Sleep状態でも使用可能な割り込みです。PWMによる割り込みは、もちろんDeep Sleep状態では使用できませんので、ここでは8番割り込みを明示的に指定しています。

Cortex-M0+側のプログラム

このプロジェクトでは、Cortex-M0+がPWMを制御しています。

main_cm0p.c
#include "project.h"

/* Clear 割り込みの処理ルーチン */
void Int_Clear_isr(void) {
    /* GPIO 出力をクリア (Low) する。 */
    Cy_GPIO_Clr(Pin_LEDR_PORT, Pin_LEDR_NUM);
}

int main(void) {
    __enable_irq(); /* 全体の割り込みを許可する */

    /* PWM の起動 */
    PWM_Start();

    /* Cortex-M4 を叩き起こして CY_CORTEX_M4_APPL_ADDR から実行させる。 */
    Cy_SysEnableCM4(CY_CORTEX_M4_APPL_ADDR); 

    /* Clear 割り込みの初期化 */
    Cy_SysInt_Init(&Int_Clear_cfg, Int_Clear_isr);
    NVIC_ClearPendingIRQ(Int_Clear_cfg.intrSrc);
    NVIC_EnableIRQ(Int_Clear_cfg.intrSrc);

    for (;;) {
    }
}

割り込み処理ルーチン(ISR)では、LEDに接続されたGPIOの出力をLowにします。これまで、ISRを定義するためにPSoC Creatorで使用され続けてきたCY_ISR()マクロは、ついに無くなりました。単純に引数と返値の無い関数を定義するだけです。PSoC 3との互換性はどうするんだろう?

main()関数では、全体の割り込みを許可した後、PWMの初期化を行っています。PSoC 4などでは普通に使われてきたコンポーネントAPIの「メソッド風の関数」は、そのほとんどがINLINE関数として定義され、これまでと類似した使い勝手を提供しています。きっと、デバッグの時に困るんだろうな。

その後、Cortex-M4を叩き起こしてInt_Clear割り込みの初期化を行っています。今までのPSoC Creatorであれば、Int_Clear_StartEx()だけで済んだのに、三行もテンプレを書かなくてはならなくなってしまいました。

Cortex-M4側のプログラム

一方、Cortex-M4側のプログラムは、以下のようになっています。

main_cm4.c
#include "project.h"

/* Set 割り込みの処理ルーチン */
void Int_Set_isr(void) {
    /* GPIO 出力をセット (High) する。 */
    Cy_GPIO_Set(Pin_LEDR_PORT, Pin_LEDR_NUM);
}

int main(void) {
    __enable_irq(); /* 全体の割り込みを許可する */

    /* Set 割り込みの初期化 */
    Cy_SysInt_Init(&Int_Set_cfg, Int_Set_isr);
    NVIC_ClearPendingIRQ(Int_Set_cfg.intrSrc);
    NVIC_EnableIRQ(Int_Set_cfg.intrSrc);

    for (;;) {
    }
}

ISRでは、LEDの接続されているGPIOをHighにしています。

main()関数で必要なのは、割り込みの初期化を行う事だけです。

これで、Lチカできました。

関連文献

AN215656 – PSoC 6 MCU Dual-Core CPU System Design
AN217666 - PSoC 6 MCU Interrupts
CE216795 - PSoC(R) 6 MCU Dual-Core Basics
PSoC 6 MCU: PSoC 63 with BLE Architecture Technical Reference Manual

関連記事

PSoC 6 のデュアルコアでLチカ (1)
PSoC 6 のデュアルコアでLチカ (2)
PSoC 6 のデュアルコアでLチカ (3)
PSoC 6 のデュアルコアでLチカ (4)