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

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

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

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

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

![GS003382.png](https://qiita-image-store.s3.amazonaws.com/0/224737/c390b9fd-b56f-37ad-11fb-68acaa09a4bb.png)

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

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

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

![GS003379.png](https://qiita-image-store.s3.amazonaws.com/0/224737/4acf0d8c-fc6a-c136-43d2-fc0b03e4ac22.png)

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

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

![GS003381.png](https://qiita-image-store.s3.amazonaws.com/0/224737/f265e3b2-d758-c370-88aa-6896217dad3e.png)

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

##**Cortex-M0+**側のプログラム

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

```c: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**側のプログラムは、以下のようになっています。

```c: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()`関数で必要なのは、割り込みの初期化を行う事だけです。

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

##関連文献
[AN215656 – PSoC 6 MCU Dual-Core CPU System Design][AN215656]
[AN217666 - PSoC 6 MCU Interrupts][AN217666]
[CE216795 - PSoC(R) 6 MCU Dual-Core Basics][CE216795]
[PSoC 6 MCU: PSoC 63 with BLE Architecture Technical Reference Manual][PSoC63BLE ATRM]

##関連記事
[PSoC 6 のデュアルコアでＬチカ (1)][(1)]
[PSoC 6 のデュアルコアでＬチカ (2)][(2)]
[PSoC 6 のデュアルコアでＬチカ (3)][(3)]
[PSoC 6 のデュアルコアでＬチカ (4)][(4)]

[PSoC Advent Calendar 2017]:https://qiita.com/advent-calendar/2017/psoc
[PSoC 6]:http://www.cypress.com/psoc6
[CY8CKIT-062-BLE]:http://www.cypress.com/cy8ckit-062-ble
[AN215656]:https://www.cypress.com/an215656
[CE216795]:https://www.cypress.com/ce216795
[AN217666]:https://www.cypress.com/an217666
[PSoC63BLE ATRM]:http://www.cypress.com/file/385621/download
[(1)]:https://qiita.com/noritan_org/items/d08f4578a91d63b93c06
[(2)]:https://qiita.com/noritan_org/items/8240f48f81b32b81a179
[(3)]:https://qiita.com/noritan_org/items/ea0ea4c933539409f2dc
[(4)]:https://qiita.com/noritan_org/items/03a360f00fd3f6988baf