LoginSignup
1
0

More than 3 years have passed since last update.

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

Last updated at Posted at 2017-12-20

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

前回のあらすじ

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

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

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

GS003377.png

この図では、SenderReceiverDataを送っています。

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

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

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

Cortex-M0+側のプログラム

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

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

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
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)

1
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0