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

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

##前回のあらすじ
[前回の記事][(3)]では、ふたつのCPUがお互いのセマフォの獲得を監視することで、Ｌチカを実現しました。しかしながら、セマフォの獲得を確実に検出できる保証がないので、**このアプリケーションに限り**動作するプログラムになってしまっています。
今回は、**Cortex-M0+**から**Cortex-M4**にメッセージを送信することにより、より確実なＬチカを行います。

##メッセージ機能のコンセプト

メッセージ機能については、[PSoC 6 MCU: PSoC 63 with BLE Architecture Technical Reference Manual][PSoC63BLE ATRM]の"Inter-Processor Communication"に記述があります。簡単に図示すると以下のようになっています。

![GS003377.png](https://qiita-image-store.s3.amazonaws.com/0/224737/5dbcadff-5e4d-8671-255b-08e455ed5180.png)

この図では、**Sender**が**Receiver**に**Data**を送っています。

1. **Sender**が**IPC Channel**を獲得して通信の権利を得ます。
2. **Sender**は、**Data**に送信すべきデータを載せます。
3. **Sender**は、**IPC Channel**の**Notify**機能によってデータを載せた事を**Receiver**に通知します。
4. **Receiver**は、**Data**からデータを取り出します。
5. **Receiver**は、**Release**機能によってデータを取り出した事を**Sender**に通知します。

以上のステップにより、**Sender**から送られたデータが**Receiver**に届けられた事を**Sender**側も確認できるようになります。

メッセージを二つ使って、自身の処理が終了した事を相手方のCPUに知らせれば、セマフォを使った時と同じようにＬチカが実現できます。
以下のプログラムでは、ステップ3の通知を**Cortex-M0+**から**Cortex-M4**への通知に、ステップ5の通知を**Cortex-M4**から**Cortex-M0+**への通知に利用することでメッセージ一つで通知の送受信を行っています。

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

このプロジェクトでは、**Cortex-M0+**がメッセージの送信役になります。

```c:main_cm0p.c
#include "project.h"

#define IPC_CHANNEL_LED  (8)  /* メッセージ送受信用の IPC チャネル番号 */

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

    /* メッセージ交換のためのハンドルを獲得する */
    ipcHandle = Cy_IPC_Drv_GetIpcBaseAddress(IPC_CHANNEL_LED);
    
    /* Cortex-M4 を叩き起こして CY_CORTEX_M4_APPL_ADDR から実行させる。 */
    Cy_SysEnableCM4(CY_CORTEX_M4_APPL_ADDR); 

    for(;;)
    {
        /* GPIO 出力をクリア (Low) する。 */
        Cy_GPIO_Clr(Pin_LEDR_PORT, Pin_LEDR_NUM);
        /* 500m秒待つ */
        CyDelay(500);
        /* GPIO 出力をセット (High) する。 */
        Cy_GPIO_Set(Pin_LEDR_PORT, Pin_LEDR_NUM);
        /* Cortex-M4にメッセージを送る */
        while (
            Cy_IPC_Drv_SendMsgWord(ipcHandle, CY_IPC_NO_NOTIFICATION, 0) != CY_IPC_DRV_SUCCESS
        );
        /* Cortex-M4の受信確認を待つ */
        while (
            Cy_IPC_Drv_IsLockAcquired(ipcHandle) == true
        );
    }
}
```

メッセージの送受信に使われるハンドラが`Cy_IPC_Drv_GetIpcBaseAddress()`関数で定義されています。この関数に与えられる引数には、IPCチャネルの番号が入ります。 IPC チャネルのうち、 0番から7番までは、システムで予約されているので、ここでは、`IPC_CHANNEL_LED=8`を使用しています。使用されているチャネルは、`Shared Files`の中の`cy_ipc_config.h`で定義されていますので参照してください。

メッセージを送信するのは、`Cy_IPC_Drv_SendMsgWord()`関数です。メッセージは32ビットのデータです。このアプリケーションでは、送るメッセージそのものに意味は無いので、便宜的に0を送っています。

**Cortex-M4**がメッセージの受信を確認したら、**IPC Channel**が解放されて、`Cy_IPC_Drv_IsLockAcquired()`関数が偽を返します。これで、一連の処理は終わりです。

##**Cortex-M4**側のプログラム

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

```c:main_cm4.c
#include "project.h"

#define IPC_CHANNEL_LED  (8)  /* メッセージ送受信用の IPC チャネル番号 */

int main(void)
{
    IPC_STRUCT_Type *ipcHandle;
    uint32_t message;

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

    /* メッセージ交換のためのハンドルを獲得する */
    ipcHandle = Cy_IPC_Drv_GetIpcBaseAddress(IPC_CHANNEL_LED);

    for(;;)
    {
        /* Cortex-M0+からメッセージが到着するのを待つ */
        while (
            Cy_IPC_Drv_ReadMsgWord(ipcHandle, &message) != CY_IPC_DRV_SUCCESS
        );
        /* GPIO 出力をクリア (Low) する。 */
        Cy_GPIO_Clr(Pin_LEDG_PORT, Pin_LEDG_NUM);
        /* 500m秒待つ */
        CyDelay(500);
        /* GPIO 出力をセット (High) する。 */
        Cy_GPIO_Set(Pin_LEDG_PORT, Pin_LEDG_NUM);
        /* Cortex-M0+にメッセージの受信確認を送る */
        CY_ASSERT(
            Cy_IPC_Drv_LockRelease(ipcHandle, CY_IPC_NO_NOTIFICATION) == CY_IPC_DRV_SUCCESS
        );
    }
}
```

ハンドルの獲得は、**Cortex-M0+**と同じです。

メッセージの到着を待つのが、`Cy_IPC_Drv_ReadMsgWord()`関数です。受信が成功したら変数`message`に値が入るはずですが、ここでは使わないので無視しています。

500m秒の処理が終わったら、`Cy_IPC_Drv_LockRelease`関数で受信確認を通知します。これで、**Cortex-M0+**側が次の処理を進められるようになります。

##割り込みは、使ってない

「メッセージ機能のコンセプト」の説明図にあった割り込みは、今回は使わずにポーリングによって処理をしています。割り込みを使えば、さらにCPUの自由時間が増えるでしょう。

##関連文献
[AN215656 – PSoC 6 MCU Dual-Core CPU System Design][AN215656]
[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 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
[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