| LPCOpen Platform v1.03 LPCOpen Platform for NXP LPC Microcontrollers

- Main Page
- Modules
- Data Structures
- Files
- Related Pages

- File List
- Globals

All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
ipc_msg.c
Go to the documentation of this file.
1 /*
2 * @brief LPC43XX Inter Processor Communication(IPC) functions
3 *
4 * @note
5 * Copyright(C) NXP Semiconductors, 2012
6 * All rights reserved.
7 *
8 * @par
9 * Software that is described herein is for illustrative purposes only
10 * which provides customers with programming information regarding the
11 * LPC products. This software is supplied "AS IS" without any warranties of
12 * any kind, and NXP Semiconductors and its licensor disclaim any and
13 * all warranties, express or implied, including all implied warranties of
14 * merchantability, fitness for a particular purpose and non-infringement of
15 * intellectual property rights. NXP Semiconductors assumes no responsibility
16 * or liability for the use of the software, conveys no license or rights under any
17 * patent, copyright, mask work right, or any other intellectual property rights in
18 * or to any products. NXP Semiconductors reserves the right to make changes
19 * in the software without notification. NXP Semiconductors also makes no
20 * representation or warranty that such application will be suitable for the
21 * specified use without further testing or modification.
22 *
23 * @par
24 * Permission to use, copy, modify, and distribute this software and its
25 * documentation is hereby granted, under NXP Semiconductors' and its
26 * licensor's relevant copyrights in the software, without fee, provided that it
27 * is used in conjunction with NXP Semiconductors microcontrollers. This
28 * copyright, permission, and disclaimer notice must appear in all copies of
29 * this code.
30 */
31
32 #include <string.h>
33 #include "lpc43xx_dualcore_config.h"
34 #include "ipc_msg.h"
35
36 #if defined(OS_FREE_RTOS)
37 #include "FreeRTOS.h"
38 #include "semphr.h"
39
40 #elif defined(OS_UCOS_III)
41 #include "os.h"
42
43 #endif
44
49 /*****************************************************************************
50 * Private types/enumerations/variables
51 ****************************************************************************/
52
53 #define SHMEMM0 LOCATE_AT(SHARED_MEM_M0)
54 #define SHMEMM4 LOCATE_AT(SHARED_MEM_M4)
55
56 /*
57 * M0 write queue
58 * This is the queue which will be written by M0 and be read by M4
59 * NOTE:
60 * This variable is put in SHMEMM0 section which will
61 * be linked to shared memory region by linker script.
62 */
63 SHMEMM0 static struct ipc_queue queue_m0 = {0};
64
65 /*
66 * M4 write queue
67 * This is the queue which will be written by M4 and be read by M0
68 * NOTE:
69 * This variable is put in SHMEMM4 section which will
70 * be linked to shared memory region by linker script.
71 */
72 SHMEMM4 static struct ipc_queue queue_m4 = {0};
73
74 /*
75 * IRQ priority of IPC interrupt
76 * Currently this has the highest priority
77 */
78 #define IPC_IRQ_Priority IRQ_PRIO_IPC
79
80 #ifdef CORE_M4
81 /*
82 * M4 read queue pointer
83 * M4 reads from this message queue based on the
84 * tail index.
85 */
86 static struct ipc_queue *qrd = &queue_m0;
87 /*
88 * M4 write queue pointer
89 * M4 writes from this message queue based on the
90 * head index.
91 */
92 static struct ipc_queue *qwr = &queue_m4;
93
94 #define IPC_IRQHandler MX_CORE_IRQHandler
95 #define ClearTXEvent Chip_CREG_ClearM0Event
96 #define IPC_IRQn M0CORE_IRQn
97
98 #elif defined(CORE_M0)
99 static struct ipc_queue *qrd = &queue_m4;
100 static struct ipc_queue *qwr = &queue_m0;
101 #define IPC_IRQHandler MX_CORE_IRQHandler
102 #define ClearTXEvent Chip_CREG_ClearM4Event
103 #define IPC_IRQn M0_M4CORE_IRQn
104
105 #else
106 #error "For LPC43XX, CORE_M0 or CORE_M4 must be defined!"
107 #endif
108
109 /* FreeRTOS functions */
110 #ifdef OS_FREE_RTOS
111 /* FreeRTOS semaphores for event handling */
112 static xSemaphoreHandle event_tx, event_rx;
113
114 #elif defined(OS_UCOS_III)
115 static OS_SEM event_tx, event_rx;
116 #endif
117
118 /*****************************************************************************
119 * Public types/enumerations/variables
120 ****************************************************************************/
121
122 /*****************************************************************************
123 * Private functions
124 ****************************************************************************/
125
126 #ifdef OS_FREE_RTOS
127 /*****************************************************************************
128 * FreeRTOS functions
129 ****************************************************************************/
130
131 /* OS specific event hanlder for FreeRTOS */
132 static void os_event_handler(void)
133 {
134 portBASE_TYPE wake1 = pdFALSE, wake2 = pdFALSE;
135
136 if (event_rx && !QUEUE_IS_EMPTY(qrd)) {
137 xSemaphoreGiveFromISR(event_rx, &wake1);
138 }
139
140 if (event_tx && !QUEUE_IS_FULL(qwr)) {
141 xSemaphoreGiveFromISR(event_tx, &wake2);
142 }
143
144 portEND_SWITCHING_ISR(wake1 || wake2);
145 }
146
147 /* Misc Init function that initializes OS semaphores */
148 static void ipc_misc_init(void)
149 {
150 vSemaphoreCreateBinary(event_tx);
151 vSemaphoreCreateBinary(event_rx);
152
153 if (!event_tx || !event_rx) {
154 DEBUGSTR("ERROR: Unable to create FreeRTOS IPC event semaphores.\r\n");
155 while (1) { /* DIE: unable to create semaphores */
156 }
157 }
158 }
159
160 /* Macro that waits till TX/RX event to happen */
161 #define ipc_wait_event(evt, sem) while ((evt)) xSemaphoreTake(sem, 100)
162 /* Macro that waits till TX/RX event to happen before tout (timeout) */
163 #define ipc_wait_event_tout(evt, tout, sem) \
164 do { \
165 while ((evt)) { \
166 if ((evt) && xSemaphoreTake(sem, tout) != pdTRUE) \
167 {tout = 0; break; }} \
168 } while (0)
169
170 #elif defined(OS_UCOS_III)
171 /*****************************************************************************
172 * uCOS-III functions
173 ****************************************************************************/
174
175 static void ipc_misc_init(void)
176 {
177 OS_ERR ret;
178 OSSemCreate(&event_tx, "TX Sema", 0, &ret);
179 if (ret != OS_ERR_NONE) {
180 while (1) {}
181 }
182 OSSemCreate(&event_rx, "RX Sema", 0, &ret);
183 if (ret != OS_ERR_NONE) {
184 while (1) {}
185 }
186 }
187
188 static void os_event_handler(void)
189 {
190 OS_ERR ret;
191 if (!QUEUE_IS_EMPTY(qrd)) {
192 OSSemPost(&event_rx, OS_OPT_POST_ALL, &ret);
193 }
194
195 if (!QUEUE_IS_FULL(qwr)) {
196 OSSemPost(&event_tx, OS_OPT_POST_ALL, &ret);
197 }
198 }
199
200 /* Wait for the event */
201 #define ipc_wait_event(evt, sem) \
202 while ((evt)) {OS_ERR ret; \
203 OSSemPend(&(sem), (OS_TICK) 100, OS_OPT_PEND_BLOCKING, (CPU_TS *) 0, &ret); }
204 #define ipc_wait_event_tout(evt, tout, sem) \
205 do { \
206 while ((evt)) { \
207 OS_ERR ret; \
208 OSSemPend(&(sem), (OS_TICK) tout, OS_OPT_PEND_BLOCKING, (CPU_TS *) 0, &ret); \
209 if ((evt) && ret == OS_ERR_TIMEOUT) {tout = 0; break; } \
210 } \
211 } while (0)
212
213 #else
214 /*****************************************************************************
215 * uCOS-III functions
216 ****************************************************************************/
217
218 static void os_event_handler(void)
219 {
220 /* Nothing to do here */
221 }
222
223 /* Wait for the event */
224 #define ipc_wait_event(evt, sem) while ((evt))
225
226 #define ipc_wait_event_tout(evt, tout, sem) \
227 do { \
228 uint32_t cnt = Chip_RIT_GetCounter(LPC_RITIMER) + (tout * (SystemCoreClock / 1000)); \
229 if (cnt + 5000 < cnt) {cnt += 5000; } \
230 while ((evt) && Chip_RIT_GetCounter(LPC_RITIMER) < cnt) {} \
231 if (evt) {tout = 0; } \
232 } while (0)
233
234 static void ipc_misc_init(void)
235 {}
236
237 #endif
238
239 /*
240 * Initiate interrupt on other processor
241 * Upon calling this function generates and interrupt on the other
242 * core. Ex. if called from M0 core it generates interrupt on M4 core
243 * and vice versa.
244 */
245 static void ipc_send_signal(void)
246 {
247 __DSB();
248 __SEV();
249 }
250
251 /*****************************************************************************
252 * Public functions
253 ****************************************************************************/
254
255 /* Function to send notificaton interrupt */
256 void IPC_msgNotify(void)
257 {
258 ipc_send_signal();
259 }
260
261 /* Function to initialize the IPC message queue */
262 void IPC_initMsgQueue(void *data, int size, int count)
263 {
264 /* Sanity Check */
265 if (!size || !count || !data) {
266 DEBUGSTR("ERROR:IPC Queue size invalid parameters\r\n");
267 while (1) {}
268 }
269
270 /* Check if size is a power of 2 */
271 if (count & (count - 1)) {
272 DEBUGSTR("ERROR:IPC Queue size not power of 2\r\n");
273 while (1) { /* BUG: Size must always be power of 2 */
274 }
275 }
276
277 memset(qwr, 0, sizeof(*qwr));
278 ipc_misc_init();
279 qwr->count = count;
280 qwr->size = size;
281 qwr->data = data;
282 qwr->valid = QUEUE_MAGIC_VALID;
283 NVIC_SetPriority(IPC_IRQn, IPC_IRQ_Priority);
284 NVIC_EnableIRQ(IPC_IRQn);
285 }
286
287 /* Function to push a message into queue with timeout */
288 int IPC_pushMsgTout(const void *data, int tout)
289 {
290 /* Check if write queue is initialized */
291 if (!QUEUE_IS_VALID(qwr)) {
292 return QUEUE_ERROR;
293 }
294
295 if (tout == 0) {
296 /* Check if queue is full */
297 if (QUEUE_IS_FULL(qwr)) {
298 return QUEUE_FULL;
299 }
300 }
301 else if (tout < 0) {
302 /* Wait for read queue to have some data */
303 ipc_wait_event(QUEUE_IS_FULL(qwr), event_tx);
304 }
305 else {
306 /* Wait for read queue to have some data */
307 ipc_wait_event_tout(QUEUE_IS_FULL(qwr), tout, event_tx);
308 if (tout == 0) {
309 return QUEUE_TIMEOUT;
310 }
311 }
312
313 memcpy(qwr->data + ((qwr->head & (qwr->count - 1)) * qwr->size), data, qwr->size);
314 qwr->head++;
315 ipc_send_signal();
316
317 return QUEUE_INSERT;
318 }
319
320 /* Function to read a message from queue with timeout */
321 int IPC_popMsgTout(void *data, int tout)
322 {
323 #ifdef EVENT_ON_RX
324 int raise_event = QUEUE_IS_FULL(qrd);
325 #endif
326
327 if (!QUEUE_IS_VALID(qrd)) {
328 return QUEUE_ERROR;
329 }
330
331 if (tout == 0) {
332 /* Check if read queue is empty */
333 if (QUEUE_IS_EMPTY(qrd)) {
334 return QUEUE_EMPTY;
335 }
336 }
337 else if (tout < 0) {
338 /* Wait for read queue to have some data */
339 ipc_wait_event(QUEUE_IS_EMPTY(qrd), event_rx);
340 }
341 else {
342 /* Wait for event or timeout */
343 ipc_wait_event_tout(QUEUE_IS_EMPTY(qrd), tout, event_rx);
344 if (tout == 0) {
345 return QUEUE_TIMEOUT;
346 }
347 }
348
349 /* Pop the queue Item */
350 memcpy(data, qrd->data + ((qrd->tail & (qrd->count - 1)) * qrd->size), qrd->size);
351 qrd->tail++;
352
353 #ifdef EVENT_ON_RX
354 if (raise_event) {
355 ipc_send_signal();
356 }
357 #endif
358 return QUEUE_VALID;
359 }
360
361 /* Get number of pending items in queue */
362 int IPC_msgPending(int queue_write)
363 {
364 struct ipc_queue *q = queue_write ? qwr : qrd;
365 if (!QUEUE_IS_VALID(q))
366 return QUEUE_ERROR;
367
368 return QUEUE_DATA_COUNT(q);
369 }
370
379 #ifdef __IAR_SYSTEMS_ICC__
380 __weak void EVENT_IPC_Receive(void)
381 #else
382 void EVENT_IPC_Receive(void) __attribute__ ((weak));
383
384 void EVENT_IPC_Receive(void)
385 #endif
386 {}
387
392 void IPC_IRQHandler(void)
393 {
394 /* Clear the interrupt */
395 ClearTXEvent();
396
397 /* Invoke OS Specific handler */
398 os_event_handler();
399
400 /* Invoke handler */
401 EVENT_IPC_Receive();
402 }
403
404 /* Function to convert IPC error number to string */
405 const char *IPC_strerror(int errnum)
406 {
407 static const char *ipc_errstr[] = {
408 "Queue Insert OK",
409 "Queue Pop OK/Valid",
410 "Queue is Full",
411 "Queue is Empty",
412 "Queue Error/Not initialized",
413 "Queue operation timed out",
414 };
415 if (errnum < 0) {
416 errnum = 1 - errnum;
417 }
418 return ipc_errstr[errnum];
419 }
420