1 /***************************************************************************//** 2 * \file cyhal_ipc.h 3 * 4 * \brief 5 * Provides a high level interface for interacting with the Infineon IPC. 6 * This interface abstracts out the chip specific details. If any chip specific 7 * functionality is necessary, or performance is critical the low level functions 8 * can be used directly. 9 * 10 ******************************************************************************** 11 * \copyright 12 * Copyright 2022 Cypress Semiconductor Corporation (an Infineon company) or 13 * an affiliate of Cypress Semiconductor Corporation 14 * 15 * SPDX-License-Identifier: Apache-2.0 16 * 17 * Licensed under the Apache License, Version 2.0 (the "License"); 18 * you may not use this file except in compliance with the License. 19 * You may obtain a copy of the License at 20 * 21 * http://www.apache.org/licenses/LICENSE-2.0 22 * 23 * Unless required by applicable law or agreed to in writing, software 24 * distributed under the License is distributed on an "AS IS" BASIS, 25 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 26 * See the License for the specific language governing permissions and 27 * limitations under the License. 28 *******************************************************************************/ 29 30 /** 31 * \addtogroup group_hal_ipc IPC (Inter-Processor Communication) 32 * \ingroup group_hal 33 * \{ 34 * High level interface for communicating between processors on a multi-core device. 35 * 36 * The IPC driver allows communication between multiple CPUs or between multiple tasks 37 * operating in different domains within a single CPU. It supports binary semaphores 38 * and message queues, similar to how they are used for task interactions in an RTOS envrionment. 39 * 40 * \section subsection_ipc_features Features 41 * * Binary semaphore for resource access control and general signalling 42 * * Message queue for passing data between tasks/cores 43 * 44 * \section subsection_ipc_quickstart Quick Start 45 * For binary semaphores, initialize the semaphore for the task/CPU. Then take/give the semaphore. 46 * For queues, only one task/CPU may initialize a queue. Other tasks/CPUs then get the handle 47 * of the created queue. Use the get/put functions to take out or put in items to the queue. 48 * 49 * \section section_ipc_snippets Code Snippets 50 * 51 * \subsection subsection_ipc_snippet1 Snippet 1: Binary semaphore example 52 * \snippet hal_ipc.c snippet_cyhal_ipc_semaphore 53 * 54 * \subsection subsection_ipc_snippet2 Snippet 2: Message queue example 55 * \snippet hal_ipc.c snippet_cyhal_ipc_queue 56 */ 57 58 #pragma once 59 60 #include "cyhal_hw_types.h" 61 #include <stdint.h> 62 #include <stdbool.h> 63 #include "cy_result.h" 64 #include "cyhal_hw_types.h" 65 66 #if defined(__cplusplus) 67 extern "C" { 68 #endif 69 70 /** \addtogroup group_hal_results_ipc IPC HAL Results 71 * IPC specific return codes 72 * \ingroup group_hal_results 73 * \{ *//** 74 */ 75 76 /** Invalid parameter error */ 77 #define CYHAL_IPC_RSLT_ERR_INVALID_PARAMETER \ 78 (CY_RSLT_CREATE_EX(CY_RSLT_TYPE_ERROR, CY_RSLT_MODULE_ABSTRACTION_HAL, CYHAL_RSLT_MODULE_IPC, 0)) 79 /** Provided queue number already used */ 80 #define CYHAL_IPC_RSLT_ERR_QUEUE_NUM_IN_USE \ 81 (CY_RSLT_CREATE_EX(CY_RSLT_TYPE_ERROR, CY_RSLT_MODULE_ABSTRACTION_HAL, CYHAL_RSLT_MODULE_IPC, 1)) 82 /** Queue is full */ 83 #define CYHAL_IPC_RSLT_ERR_QUEUE_FULL \ 84 (CY_RSLT_CREATE_EX(CY_RSLT_TYPE_ERROR, CY_RSLT_MODULE_ABSTRACTION_HAL, CYHAL_RSLT_MODULE_IPC, 2)) 85 /** Queue is empty */ 86 #define CYHAL_IPC_RSLT_ERR_QUEUE_EMPTY \ 87 (CY_RSLT_CREATE_EX(CY_RSLT_TYPE_ERROR, CY_RSLT_MODULE_ABSTRACTION_HAL, CYHAL_RSLT_MODULE_IPC, 3)) 88 /** Queue object is not found */ 89 #define CYHAL_IPC_RSLT_ERR_QUEUE_NOT_FOUND \ 90 (CY_RSLT_CREATE_EX(CY_RSLT_TYPE_ERROR, CY_RSLT_MODULE_ABSTRACTION_HAL, CYHAL_RSLT_MODULE_IPC, 4)) 91 /** IPC interrupt was enabled for one of the cores, but was not (yet) handled */ 92 #define CYHAL_IPC_RSLT_ERR_ISR_WAS_NOT_HANDLED \ 93 (CY_RSLT_CREATE_EX(CY_RSLT_TYPE_ERROR, CY_RSLT_MODULE_ABSTRACTION_HAL, CYHAL_RSLT_MODULE_IPC, 5)) 94 /** Operation can't be performed in ISR context */ 95 #define CYHAL_IPC_RSLT_ERR_CANT_OPERATE_IN_ISR \ 96 (CY_RSLT_CREATE_EX(CY_RSLT_TYPE_ERROR, CY_RSLT_MODULE_ABSTRACTION_HAL, CYHAL_RSLT_MODULE_IPC, 6)) 97 98 /** 99 * \} 100 */ 101 102 /** This define can be used as timeout argument for the IPC HAL driver functions, that take timeout 103 * as input parameter, in order to make function never time out (wait forever) */ 104 #define CYHAL_IPC_NEVER_TIMEOUT (0xFFFFFFFFUL) 105 106 /** Flags enum of IPC events. Multiple events can be enabled via \ref cyhal_ipc_queue_enable_event and 107 * the callback from \ref cyhal_ipc_queue_register_callback will be run to notify. */ 108 typedef enum 109 { 110 CYHAL_IPC_NO_INTR = 0, //!< No interrupt 111 CYHAL_IPC_QUEUE_WRITE = 1 << 0, //!< New item was written to the queue 112 CYHAL_IPC_QUEUE_READ = 1 << 1, //!< New item was read from the queue 113 CYHAL_IPC_QUEUE_FULL = 1 << 2, //!< Queue is full 114 CYHAL_IPC_QUEUE_EMPTY = 1 << 3, //!< Queue is empty 115 CYHAL_IPC_QUEUE_RESET = 1 << 4, //!< Queue was reset 116 } cyhal_ipc_event_t; 117 118 /** Event handler for IPC interrupts */ 119 typedef void (*cyhal_ipc_event_callback_t)(void *callback_arg, cyhal_ipc_event_t event); 120 121 /** IPC queue structure element 122 */ 123 typedef struct cyhal_ipc_queue_s 124 { 125 uint32_t channel_num; //!< IPC channel number (e.g. CYHAL_IPC_CHAN_0) (populated by user during initialization) 126 uint32_t queue_num; //!< Queue number (populated by user during initialization) 127 void *queue_pool; //!< Pointer to the queue pool (populated by user during initialization). This is pointer to shared memory, in which queue elements will be stored. CYHAL_IPC_QUEUE_POOL_ALLOC macro can be used to allocate memory for pool. 128 uint32_t num_items; //!< Maximum number of items allowed in the queue (populated by user during initialization) 129 uint32_t item_size; //!< Size of each item in the queue (populated by user during initialization) 130 uint32_t curr_items; //!< Current number of items in the queue (not expected to be modified by user) 131 void *queue_head; //!< Pointer to the queue head in circular buffer (not expected to be modified by user) 132 void *queue_tail; //!< Pointer to the queue tail in circular buffer (not expected to be modified by user) 133 uint32_t triggered_events; //!< Events, that were triggered by latest performed operation (not expected to be modified by user) 134 struct cyhal_ipc_queue_s *next_queue_obj; //!< Pointer to the next queue object (not expected to be modified by user) 135 #if defined (__DCACHE_PRESENT) && (__DCACHE_PRESENT == 1U) 136 uint32_t padding[6]; //!< Necessary to make sure the total size is a multiple of __SCB_DCACHE_LINE_SIZE 137 #endif 138 }cyhal_ipc_queue_t; 139 140 /** Creates a single semaphore based on a given number. 141 * 142 * This function must be called by all tasks/CPUs accessing the semaphore. 143 * @param[out] obj Pointer to an IPC object. The caller must allocate the memory for this object but the 144 * init function will initialize its contents. 145 * @param[in] semaphore_num The semaphore number to initialize. 146 * @param[in] preemptable Allows whether the semaphore can be preempted by another task. 147 * @return The status of the init request 148 */ 149 cy_rslt_t cyhal_ipc_semaphore_init(cyhal_ipc_t *obj, uint32_t semaphore_num, bool preemptable); 150 151 /** Frees the IPC semaphore. 152 * 153 * This function frees the resources associated with the semaphore. 154 * @param[in, out] obj The IPC object. 155 */ 156 void cyhal_ipc_semaphore_free(cyhal_ipc_t *obj); 157 158 /** Takes/acquires a semaphore. 159 * 160 * If the semaphore is available, it is acquired and this function and returns. 161 * This function has a timeout argument (in microseconds). If the semaphore is not available, it blocks until it 162 * times out or succeeds in acquiring it. 163 * @param[in] obj The IPC object. 164 * @param[in] timeout_us Timeout in microseconds. Value 0 can be used if no timeout needed while 165 * \ref CYHAL_IPC_NEVER_TIMEOUT can be used to make function block until semaphore is successfully taken. 166 * @return The status of the take request 167 */ 168 cy_rslt_t cyhal_ipc_semaphore_take(cyhal_ipc_t *obj, uint32_t timeout_us); 169 170 /** Gives/releases a semaphore. 171 * 172 * The semaphore is released allowing other tasks waiting on the semaphore to take it. 173 * @param[in] obj The IPC object. 174 * @return The status of the give request 175 */ 176 cy_rslt_t cyhal_ipc_semaphore_give(cyhal_ipc_t *obj); 177 178 /** Creates a new queue for a given IPC channel based on the given queue number and other parameters. 179 * 180 * This function requires \ref cyhal_ipc_queue_t (queue handle) pointer to shared memory. Some elements of cyhal_ipc_queue_t 181 * structure are expected to be filled by user. One key element of the structure to be filled by user is a pointer to 182 * the queue pool allocated in the shared memory. 183 * Queue handle is used by other tasks/CPUs to refer to the queue. Note that this function must be called only by one 184 * of the tasks/CPUs for the same IPC channel. This CPU can call the function multiple times for the same IPC 185 * channel, but with a different queue number. 186 * \note CYHAL_IPC_QUEUE_HANDLE_ALLOC and CYHAL_IPC_QUEUE_POOL_ALLOC macro can be used in order to allocate 187 * memory for (respectively) queue handle (cyhal_ipc_queue_t) and queue pool in shared section. Please refer to 188 * \ref subsection_ipc_snippet2 for initialization guidance. 189 * @param[out] obj Pointer to an IPC object. The caller must allocate the memory for this object 190 * but the init function will initialize its contents. 191 * @param[in] queue_handle Queue handle. Fields channel_num, queue_num, queue_pool, num_items and item_size 192 * are expected to be filled by user before initialization. Please refer to \ref subsection_ipc_snippet2 for 193 * initialization guidance. 194 * @return The status of the init request 195 */ 196 cy_rslt_t cyhal_ipc_queue_init(cyhal_ipc_t *obj, cyhal_ipc_queue_t *queue_handle); 197 198 /** Frees the queue. 199 * 200 * This operation only removes the queue handle from the list of available queues. The queue pool and the queue 201 * handle allocated in the shared memory needs to be freed (if dynamically allocated) by the application. 202 * @param[in, out] obj The IPC object 203 */ 204 void cyhal_ipc_queue_free(cyhal_ipc_t *obj); 205 206 /** Gets a handle pointer for a given IPC channel and queue number. 207 * 208 * This function should be called by other tasks/CPUs that have not called the initialization function. 209 * @param[out] obj The IPC object handle. 210 * @param[in] channel_num IPC channel to use for the queue messaging. 211 * @param[in] queue_num Queue number. 212 * @return The status of the get handle request 213 */ 214 cy_rslt_t cyhal_ipc_queue_get_handle(cyhal_ipc_t *obj, uint32_t channel_num, uint32_t queue_num); 215 216 /** Registers a callback to be executed when certain events occur. 217 * 218 * @param[in] obj The IPC object. 219 * @param[in] callback The callback handler which will be invoked when an event triggers. 220 * @param[in] callback_arg Generic argument that will be provided to the callback when called. 221 */ 222 void cyhal_ipc_queue_register_callback(cyhal_ipc_t *obj, cyhal_ipc_event_callback_t callback, void *callback_arg); 223 224 /** Enables which events trigger the callback execution. 225 * 226 * It can trigger when a new item is written to the queue, read from the queue, when the queue becomes full, 227 * when the queue becomes empty or when there is a reset. Note that these events might execute callbacks 228 * associated to all queues that belong to an IPC channel. When defining the ISR priority, the last call to 229 * this function overwrites the priority for all queue callbacks registered to the same IPC channel. 230 * @param[in] obj The IPC object 231 * @param[in] event The IPC event type 232 * @param[in] intr_priority The priority for NVIC interrupt events 233 * @param[in] enable True to turn on specified events, False to turn off 234 */ 235 void cyhal_ipc_queue_enable_event(cyhal_ipc_t *obj, cyhal_ipc_event_t event, uint8_t intr_priority, bool enable); 236 237 /** Adds one item to the queue. 238 * 239 * This function can be called by any task/CPU. This function has a timeout argument (in microseconds). 240 * If the queue is full, it stays there until it times out or the queue is no longer full. 241 * This function can be blocking or non-blocking (timeout set to ZERO). 242 * @param[in] obj The IPC object 243 * @param[in] msg Location of message queue item 244 * @param[in] timeout_us Timeout in microseconds. Value 0 can be used if no timeout needed while 245 * \ref CYHAL_IPC_NEVER_TIMEOUT can be used to make function block until element is successfully put into the queue. 246 * @return The status of the put request 247 */ 248 cy_rslt_t cyhal_ipc_queue_put(cyhal_ipc_t *obj, void *msg, uint32_t timeout_us); 249 250 /** Removes one item from the queue. 251 * 252 * This function can be called by any task/CPU. This function has a timeout argument (in microseconds). 253 * If the queue is empty, it stays there until it times out or the queue receives a new item. 254 * This function can be blocking or non-blocking (timeout set to ZERO). 255 * @param[in] obj The IPC object 256 * @param[out] msg Location of message queue item 257 * @param[in] timeout_us Timeout in microseconds. Value 0 can be used if no timeout needed while 258 * \ref CYHAL_IPC_NEVER_TIMEOUT can be used to make function block until element is successfully taken from the queue. 259 * @return The status of the get request 260 */ 261 cy_rslt_t cyhal_ipc_queue_get(cyhal_ipc_t *obj, void *msg, uint32_t timeout_us); 262 263 /** Returns how many items are in the queue. 264 * 265 * This function can be called by any task/CPU. 266 * @param[in] obj The IPC object 267 * @return Number of items in the queue 268 */ 269 uint32_t cyhal_ipc_queue_count(cyhal_ipc_t *obj); 270 271 /** Clear all the items in the queue. 272 * 273 * This function can be called by the any task/CPU. 274 * @param[in] obj The IPC object 275 * @return The status of the reset request 276 */ 277 cy_rslt_t cyhal_ipc_queue_reset(cyhal_ipc_t *obj); 278 279 #if defined(__cplusplus) 280 } 281 #endif 282 283 #ifdef CYHAL_IPC_IMPL_HEADER 284 #include CYHAL_IPC_IMPL_HEADER 285 #endif /* CYHAL_IPC_IMPL_HEADER */ 286 287 /** \} group_hal_ipc */ 288