/** \file * \brief This file implements messaging using inter-processor communication (IPC). * * \see https://community.cypress.com/thread/36182. */ /** * \ingroup CONSOLE */ /* Include Files */ #include #include #include #include #include #include #include "COMM_IPC_Messages.h" /* Private Function Prototypes */ #if (__CORTEX_M == 0) static void Message_Received_for_CM0(uint32_t * msg); static void Message_Received_by_CM4(void); #endif // (__CORTEX_M == 0) #if (__CORTEX_M == 4) static void Message_Received_for_CM4(uint32_t * msg); static void Message_Received_by_CM0(void); #endif // (__CORTEX_M == 4) static void IPC_UserPipeInit(void); static void IPC_UserPipeISR(void); /* Local Definitions and Constants */ //! Number of clients supported on the user pipe. #define CY_IPC_USRPIPE_CLIENT_CNT (uint32_t)(8u) #define CY_IPC_CHAN_USRPIPE_CM0 (uint32_t)(8u) #define CY_IPC_CHAN_USRPIPE_CM4 (uint32_t)(9u) #define CY_IPC_INTR_USRPIPE_CM0 (uint32_t)(8u) #define CY_IPC_INTR_USRPIPE_CM4 (uint32_t)(9u) #define CY_IPC_EP_USRPIPE_ADDR_CM0_EP (uint32_t)(2u) #define CY_IPC_EP_USRPIPE_ADDR_CM4_EP (uint32_t)(3u) #if (CY_CPU_CORTEX_M0P) #define IPC_EP_USRPIPE_ADDR CY_IPC_EP_USRPIPE_ADDR_CM0_EP #else #define IPC_EP_USRPIPE_ADDR CY_IPC_EP_USRPIPE_ADDR_CM4_EP #endif /* (CY_CPU_CORTEX_M0P) */ /* User Pipe Configuration */ #define IPC_USRPIPE_CHAN_MASK_CM0 (uint32_t)(0x0001ul << CY_IPC_CHAN_USRPIPE_CM0) #define IPC_USRPIPE_CHAN_MASK_CM4 (uint32_t)(0x0001ul << CY_IPC_CHAN_USRPIPE_CM4) #define IPC_USRPIPE_INTR_MASK (uint32_t)( IPC_USRPIPE_CHAN_MASK_CM0 | IPC_USRPIPE_CHAN_MASK_CM4 ) #define IPC_INTR_USRPIPE_PRIOR_CM0 (uint32_t)(1u) /* Notifier Priority */ #define IPC_INTR_USRPIPE_PRIOR_CM4 (uint32_t)(1u) /* Notifier Priority */ #define IPC_INTR_USRPIPE_MUX_CM0 (uint32_t)(7u) /* IPC CYPRESS PIPE */ #define IPC_USRPIPE_CONFIG_CM0 (uint32_t)(IPC_USRPIPE_INTR_MASK << CY_IPC_PIPE_CFG_IMASK_Pos)\ |(CY_IPC_INTR_USRPIPE_CM0 << CY_IPC_PIPE_CFG_INTR_Pos )\ |(CY_IPC_CHAN_USRPIPE_CM0) #define IPC_USRPIPE_CONFIG_CM4 (uint32_t)(IPC_USRPIPE_INTR_MASK << CY_IPC_PIPE_CFG_IMASK_Pos)\ |(CY_IPC_INTR_USRPIPE_CM4 << CY_IPC_PIPE_CFG_INTR_Pos )\ |(CY_IPC_CHAN_USRPIPE_CM4) #define USRPIPE_CONFIG \ {\ /* .ep0ConfigData */ {\ /* .ipcNotifierNumber */ CY_IPC_INTR_USRPIPE_CM0,\ /* .ipcNotifierPriority */ IPC_INTR_USRPIPE_PRIOR_CM0,\ /* .ipcNotifierMuxNumber */ IPC_INTR_USRPIPE_MUX_CM0,\ /* .epAddress */ CY_IPC_EP_USRPIPE_ADDR_CM0_EP,\ /* .epConfig */ IPC_USRPIPE_CONFIG_CM0\ },\ /* .ep1ConfigData */ {\ /* .ipcNotifierNumber */ CY_IPC_INTR_USRPIPE_CM4,\ /* .ipcNotifierPriority */ IPC_INTR_USRPIPE_PRIOR_CM4,\ /* .ipcNotifierMuxNumber */ 0u,\ /* .epAddress */ CY_IPC_EP_USRPIPE_ADDR_CM4_EP,\ /* .epConfig */ IPC_USRPIPE_CONFIG_CM4\ },\ /* .endpointClientsCount */ CY_IPC_USRPIPE_CLIENT_CNT,\ /* .endpointsCallbacksArray */ ipc_pipe_CbArray,\ /* .userPipeIsrHandler */ &IPC_UserPipeISR\ } //! Client ID for messages from the CM0 to the CM4 #define COMM_IPC_CM0_TO_CM4_CLIENT_ID 0 //! Client ID for messages from the CM4 to the CM0 #define COMM_IPC_CM4_TO_CM0_CLIENT_ID 1 /* Public Variables */ /* Private Variables */ #if (__CORTEX_M == 0) static COMM_IPCMessage_T MessageBuffer = { .ClientID = _VAL2FLD(CY_IPC_PIPE_MSG_CLIENT, COMM_IPC_CM0_TO_CM4_CLIENT_ID) | _VAL2FLD(CY_IPC_PIPE_MSG_USR, 0) | _VAL2FLD(CY_IPC_PIPE_MSG_RELEASE, IPC_USRPIPE_INTR_MASK), .MessageID = COMM_SMM_DefaultNoMessage, .Data = NULL }; static volatile bool OK_to_send_from_CM0_to_CM4 = true; #endif // (__CORTEX_M == 0) #if (__CORTEX_M == 4) static COMM_IPCMessage_T MessageBuffer = { .ClientID = _VAL2FLD(CY_IPC_PIPE_MSG_CLIENT, COMM_IPC_CM4_TO_CM0_CLIENT_ID) | _VAL2FLD(CY_IPC_PIPE_MSG_USR, 0) | _VAL2FLD(CY_IPC_PIPE_MSG_RELEASE, IPC_USRPIPE_INTR_MASK), .MessageID = COMM_SMM_DefaultNoMessage, .Data = NULL }; static volatile bool OK_to_send_from_CM4_to_CM0 = true; #endif // (__CORTEX_M == 4) /* Public Functions */ #if (__CORTEX_M == 0) //! Initializes the inter-processor communications on the Cortex-M0 core. /*! * This should be called *before* calling Cy_SysEnableCM4(). */ void COMM_InitIPCMessages(void) { IPC_UserPipeInit(); // Register a callback to handle messages from CM4. Cy_IPC_Pipe_RegisterCallback(IPC_EP_USRPIPE_ADDR, Message_Received_for_CM0, CY_IPC_EP_CYPIPE_CM4_ADDR); } #endif // (__CORTEX_M == 0) #if (__CORTEX_M == 4) //! Initializes the inter-processor communications on the Cortex-M4 core. void COMM_InitIPCMessages(void) { IPC_UserPipeInit(); // Register a callback to handle messages from CM0. Cy_IPC_Pipe_RegisterCallback(IPC_EP_USRPIPE_ADDR, Message_Received_for_CM4, CY_IPC_EP_CYPIPE_CM0_ADDR); } #endif // (__CORTEX_M == 4) //! Sends an inter-processor communication message to the other core. bool COMM_SendMessageToOtherCore(COMM_IPCMessageID_T message_ID, void * message_data) { bool message_sent = false; MessageBuffer.MessageID = message_ID; MessageBuffer.Data = message_data; #if (__CORTEX_M == 0) if (OK_to_send_from_CM0_to_CM4 == true) { OK_to_send_from_CM0_to_CM4 = false; uint32_t timeout_in_us = 2000; cy_en_ipc_pipe_status_t ipcStatus; do { ipcStatus = Cy_IPC_Pipe_SendMessage(CY_IPC_EP_USRPIPE_ADDR_CM4_EP, CY_IPC_EP_USRPIPE_ADDR_CM0_EP, (uint32_t *) &MessageBuffer, Message_Received_by_CM4); Cy_SysLib_DelayUs(1u); timeout_in_us--; } while((ipcStatus != CY_IPC_PIPE_SUCCESS) && (timeout_in_us != 0)); message_sent = true; } #endif // (__CORTEX_M == 0) #if (__CORTEX_M == 4) if (OK_to_send_from_CM4_to_CM0 == true) { OK_to_send_from_CM4_to_CM0 = false; uint32_t timeout_in_us = 2000; cy_en_ipc_pipe_status_t ipcStatus; do { ipcStatus = Cy_IPC_Pipe_SendMessage(CY_IPC_EP_USRPIPE_ADDR_CM0_EP, CY_IPC_EP_USRPIPE_ADDR_CM4_EP, (uint32_t *) &MessageBuffer, Message_Received_by_CM0); Cy_SysLib_DelayUs(1u); timeout_in_us--; } while((ipcStatus != CY_IPC_PIPE_SUCCESS) && (timeout_in_us != 0)); message_sent = true; } #endif // (__CORTEX_M == 4) return message_sent; } /* Private Functions */ #if (__CORTEX_M == 0) //! Callback for messages received by the CM0 core from the CM4 core. /*! * \note This code is executed inside an interrupt handler. */ static void Message_Received_for_CM0(uint32_t * msg) { switch (((COMM_IPCMessage_T *)msg)->MessageID) { default: case COMM_SMM_DefaultNoMessage: case COMM_SMM_NoMessage: break; case COMM_SMM_RebootImmediately: // Perform a software reset of both cores. NVIC_SystemReset(); break; } } static void Message_Received_by_CM4(void) { OK_to_send_from_CM0_to_CM4 = true; } #endif // (__CORTEX_M == 0) #if (__CORTEX_M == 4) //! Callback for messages received by the CM4 core from the CM0 core. /*! * \note This code is executed inside an interrupt handler. */ static void Message_Received_for_CM4(uint32_t * msg) { switch (((COMM_IPCMessage_T *)msg)->MessageID) { default: case COMM_SMM_DefaultNoMessage: case COMM_SMM_NoMessage: break; case COMM_SMM_RebootImmediately: // This message does nothing on CM4 break; } } static void Message_Received_by_CM0(void) { OK_to_send_from_CM4_to_CM0 = true; } #endif // (__CORTEX_M == 4) //! Initializes the IPC user pipe. static void IPC_UserPipeInit(void) { static cy_ipc_pipe_callback_ptr_t ipc_pipe_CbArray[CY_IPC_USRPIPE_CLIENT_CNT]; static const cy_stc_ipc_pipe_config_t userPipeConfig = USRPIPE_CONFIG; uint32_t savedIntrStatus = Cy_SysLib_EnterCriticalSection(); Cy_IPC_Pipe_Init(&userPipeConfig); Cy_SysLib_ExitCriticalSection(savedIntrStatus); } //! Interrupt service routine for the user pipe. void IPC_UserPipeISR(void) { Cy_IPC_Pipe_ExecuteCallback(IPC_EP_USRPIPE_ADDR); }