これは、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"に記述があります。簡単に図示すると以下のようになっています。
この図では、SenderがReceiverにDataを送っています。
- SenderがIPC Channelを獲得して通信の権利を得ます。
- Senderは、Dataに送信すべきデータを載せます。
- Senderは、IPC ChannelのNotify機能によってデータを載せた事をReceiverに通知します。
- Receiverは、Dataからデータを取り出します。
- Receiverは、Release機能によってデータを取り出した事をSenderに通知します。
以上のステップにより、Senderから送られたデータがReceiverに届けられた事をSender側も確認できるようになります。
メッセージを二つ使って、自身の処理が終了した事を相手方のCPUに知らせれば、セマフォを使った時と同じようにLチカが実現できます。
以下のプログラムでは、ステップ3の通知をCortex-M0+からCortex-M4への通知に、ステップ5の通知をCortex-M4から**Cortex-M0+**への通知に利用することでメッセージ一つで通知の送受信を行っています。
##**Cortex-M0+**側のプログラム
このプロジェクトでは、**Cortex-M0+**がメッセージの送信役になります。
#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側のプログラムは、以下のようになっています。
#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)