2 * FreeRTOS Kernel V10.0.1
\r
3 * Copyright (C) 2017 Amazon.com, Inc. or its affiliates. All Rights Reserved.
\r
5 * Permission is hereby granted, free of charge, to any person obtaining a copy of
\r
6 * this software and associated documentation files (the "Software"), to deal in
\r
7 * the Software without restriction, including without limitation the rights to
\r
8 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
\r
9 * the Software, and to permit persons to whom the Software is furnished to do so,
\r
10 * subject to the following conditions:
\r
12 * The above copyright notice and this permission notice shall be included in all
\r
13 * copies or substantial portions of the Software.
\r
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
\r
16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
\r
17 * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
\r
18 * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
\r
19 * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
\r
20 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
\r
22 * http://www.FreeRTOS.org
\r
23 * http://aws.amazon.com/freertos
\r
25 * 1 tab == 4 spaces!
\r
29 * An example that mimics a message buffer being used to pass data from one core
\r
30 * to another. The core that sends the data is referred to as core A. The core
\r
31 * that receives the data is referred to as core B. The task implemented by
\r
32 * prvCoreATask() runs on core A. Two instances of the task implemented by
\r
33 * prvCoreBTasks() run on core B. prvCoreATask() sends messages via message
\r
34 * buffers to both instances of prvCoreBTasks(), one message buffer per channel.
\r
35 * A third message buffer is used to pass the handle of the message buffer
\r
36 * written to by core A to an interrupt service routine that is triggered by
\r
37 * core A but executes on core B.
\r
39 * The example relies on the FreeRTOS provided default implementation of
\r
40 * sbSEND_COMPLETED() being overridden by an implementation in FreeRTOSConfig.h
\r
41 * that writes the handle of the message buffer that contains data into the
\r
42 * control message buffer, then generates an interrupt in core B. The necessary
\r
43 * implementation is provided in this file and can be enabled by adding the
\r
44 * following to FreeRTOSConfig.h:
\r
46 * #define sbSEND_COMPLETED( pxStreamBuffer ) vGenerateCoreBInterrupt( pxStreamBuffer )
\r
48 * Core to core communication via message buffer requires the message buffers
\r
49 * to be at an address known to both cores within shared memory.
\r
51 * Note that, while this example uses three message buffers, the same
\r
52 * functionality can be implemented using a single message buffer by using the
\r
53 * same design pattern described on the link below for queues, but using message
\r
54 * buffers instead. It is actually simpler with a message buffer as variable
\r
55 * length data can be written into the message buffer directly:
\r
56 * http://www.freertos.org/Pend-on-multiple-rtos-objects.html#alternative_design_pattern
\r
59 /* Standard includes. */
\r
63 /* FreeRTOS includes. */
\r
64 #include "FreeRTOS.h"
\r
66 #include "message_buffer.h"
\r
68 /* Demo app includes. */
\r
69 #include "MessageBufferAMP.h"
\r
71 /* Enough for 3 4 byte pointers, including the additional 4 bytes per message
\r
72 overhead of message buffers. */
\r
73 #define mbaCONTROL_MESSAGE_BUFFER_SIZE ( 24 )
\r
75 /* Enough four 4 8 byte strings, plus the additional 4 bytes per message
\r
76 overhead of message buffers. */
\r
77 #define mbaTASK_MESSAGE_BUFFER_SIZE ( 60 )
\r
79 /* The number of instances of prvCoreBTasks that are created. */
\r
80 #define mbaNUMBER_OF_CORE_B_TASKS 2
\r
82 /* A block time of 0 simply means, don't block. */
\r
83 #define mbaDONT_BLOCK 0
\r
85 /* Macro that mimics an interrupt service routine executing by simply calling
\r
86 the routine inline. */
\r
87 #define mbaGENERATE_CORE_B_INTERRUPT() prvCoreBInterruptHandler()
\r
89 /*-----------------------------------------------------------*/
\r
92 * Implementation of the task that, on a real dual core device, would run on
\r
93 * core A and send message to tasks running on core B.
\r
95 static void prvCoreATask( void *pvParameters );
\r
98 * Implementation of the task that, on a real dual core device, would run on
\r
99 * core B and receive message from core A. The demo creates two instances of
\r
102 static void prvCoreBTasks( void *pvParameters );
\r
105 * The function that, on a real dual core device, would handle inter-core
\r
106 * interrupts, but in this case is just called inline.
\r
108 static void prvCoreBInterruptHandler( void );
\r
110 /*-----------------------------------------------------------*/
\r
112 /* The message buffers used to pass data from core A to core B. */
\r
113 static MessageBufferHandle_t xCoreBMessageBuffers[ mbaNUMBER_OF_CORE_B_TASKS ];
\r
115 /* The control message buffer. This is used to pass the handle of the message
\r
116 message buffer that holds application data into the core to core interrupt
\r
117 service routine. */
\r
118 static MessageBufferHandle_t xControlMessageBuffer;
\r
120 /* Counters used to indicate to the check that the tasks are still executing. */
\r
121 static uint32_t ulCycleCounters[ mbaNUMBER_OF_CORE_B_TASKS ];
\r
123 /* Set to pdFALSE if any errors are detected. Used to inform the check task
\r
124 that something might be wrong. */
\r
125 BaseType_t xDemoStatus = pdPASS;
\r
127 /*-----------------------------------------------------------*/
\r
129 void vStartMessageBufferAMPTasks( void )
\r
133 xControlMessageBuffer = xMessageBufferCreate( mbaCONTROL_MESSAGE_BUFFER_SIZE );
\r
135 xTaskCreate( prvCoreATask, /* The function that implements the task. */
\r
136 "AMPCoreA", /* Human readable name for the task. */
\r
137 configMINIMAL_STACK_SIZE, /* Stack size (in words!). */
\r
138 NULL, /* Task parameter is not used. */
\r
139 tskIDLE_PRIORITY, /* The priority at which the task is created. */
\r
140 NULL ); /* No use for the task handle. */
\r
142 for( x = 0; x < mbaNUMBER_OF_CORE_B_TASKS; x++ )
\r
144 xCoreBMessageBuffers[ x ] = xMessageBufferCreate( mbaTASK_MESSAGE_BUFFER_SIZE );
\r
145 configASSERT( xCoreBMessageBuffers[ x ] );
\r
147 /* Pass the loop counter into the created task using the task's
\r
148 parameter. The task then uses the value as an index into the
\r
149 ulCycleCounters and xCoreBMessageBuffers arrays. */
\r
150 xTaskCreate( prvCoreBTasks,
\r
152 configMINIMAL_STACK_SIZE,
\r
154 tskIDLE_PRIORITY + 1,
\r
158 /*-----------------------------------------------------------*/
\r
160 static void prvCoreATask( void *pvParameters )
\r
163 uint32_t ulNextValue = 0;
\r
164 const TickType_t xDelay = pdMS_TO_TICKS( 250 );
\r
165 char cString[ 15 ]; /* At least large enough to hold "4294967295\0" (0xffffffff). */
\r
167 /* Remove warning about unused parameters. */
\r
168 ( void ) pvParameters;
\r
172 /* Create the next string to send. The value is incremented on each
\r
173 loop iteration, and the length of the string changes as the number of
\r
174 digits in the value increases. */
\r
175 sprintf( cString, "%lu", ( unsigned long ) ulNextValue );
\r
177 /* Send the value from this (pseudo) Core A to the tasks on the (pseudo)
\r
178 Core B via the message buffers. This will result in sbSEND_COMPLETED()
\r
179 being executed, which in turn will write the handle of the message
\r
180 buffer written to into xControlMessageBuffer then generate an interrupt
\r
182 for( x = 0; x < mbaNUMBER_OF_CORE_B_TASKS; x++ )
\r
184 xMessageBufferSend( /* The message buffer to write to. */
\r
185 xCoreBMessageBuffers[ x ],
\r
186 /* The source of the data to send. */
\r
187 ( void * ) cString,
\r
188 /* The length of the data to send. */
\r
190 /* The block time, should the buffer be full. */
\r
194 /* Delay before repeating with a different and potentially different
\r
196 vTaskDelay( xDelay );
\r
200 /*-----------------------------------------------------------*/
\r
202 static void prvCoreBTasks( void *pvParameters )
\r
205 size_t xReceivedBytes;
\r
206 uint32_t ulNextValue = 0;
\r
207 char cExpectedString[ 15 ]; /* At least large enough to hold "4294967295\0" (0xffffffff). */
\r
208 char cReceivedString[ 15 ];
\r
210 /* The index into the xCoreBMessageBuffers and ulLoopCounter arrays is
\r
211 passed into this task using the task's parameter. */
\r
212 x = ( BaseType_t ) pvParameters;
\r
213 configASSERT( x < mbaNUMBER_OF_CORE_B_TASKS );
\r
217 /* Create the string that is expected to be received this time round. */
\r
218 sprintf( cExpectedString, "%lu", ( unsigned long ) ulNextValue );
\r
220 /* Wait to receive the next message from core A. */
\r
221 memset( cReceivedString, 0x00, sizeof( cReceivedString ) );
\r
222 xReceivedBytes = xMessageBufferReceive( /* The message buffer to receive from. */
\r
223 xCoreBMessageBuffers[ x ],
\r
224 /* Location to store received data. */
\r
226 /* Maximum number of bytes to receive. */
\r
227 sizeof( cReceivedString ),
\r
228 /* Ticks to wait if buffer is empty. */
\r
231 /* Check the number of bytes received was as expected. */
\r
232 configASSERT( xReceivedBytes == strlen( cExpectedString ) );
\r
233 ( void ) xReceivedBytes; /* Incase configASSERT() is not defined. */
\r
235 /* If the received string matches that expected then increment the loop
\r
236 counter so the check task knows this task is still running. */
\r
237 if( strcmp( cReceivedString, cExpectedString ) == 0 )
\r
239 ( ulCycleCounters[ x ] )++;
\r
243 xDemoStatus = pdFAIL;
\r
246 /* Expect the next string in sequence the next time around. */
\r
250 /*-----------------------------------------------------------*/
\r
252 /* Called by the reimplementation of sbSEND_COMPLETED(), which can be defined
\r
253 as follows in FreeRTOSConfig.h:
\r
254 #define sbSEND_COMPLETED( pxStreamBuffer ) vGenerateCoreBInterrupt( pxStreamBuffer )
\r
256 void vGenerateCoreBInterrupt( void * xUpdatedMessageBuffer )
\r
258 MessageBufferHandle_t xUpdatedBuffer = ( MessageBufferHandle_t ) xUpdatedMessageBuffer;
\r
260 /* If sbSEND_COMPLETED() has been implemented as above, then this function
\r
261 is called from within xMessageBufferSend(). As this function also calls
\r
262 xMessageBufferSend() itself it is necessary to guard against a recursive
\r
263 call. If the message buffer just updated is the message buffer written to
\r
264 by this function, then this is a recursive call, and the function can just
\r
265 exit without taking further action. */
\r
266 if( xUpdatedBuffer != xControlMessageBuffer )
\r
268 /* Use xControlMessageBuffer to pass the handle of the message buffer
\r
269 written to by core A to the interrupt handler about to be generated in
\r
271 xMessageBufferSend( xControlMessageBuffer, &xUpdatedBuffer, sizeof( xUpdatedBuffer ), mbaDONT_BLOCK );
\r
273 /* This is where the interrupt would be generated. In this case it is
\r
274 not a genuine interrupt handler that executes, just a standard function
\r
276 mbaGENERATE_CORE_B_INTERRUPT();
\r
279 /*-----------------------------------------------------------*/
\r
281 /* Handler for the interrupts that are triggered on core A but execute on core
\r
283 static void prvCoreBInterruptHandler( void )
\r
285 MessageBufferHandle_t xUpdatedMessageBuffer;
\r
286 BaseType_t xHigherPriorityTaskWoken = pdFALSE;
\r
288 /* xControlMessageBuffer contains the handle of the message buffer that
\r
290 if( xMessageBufferReceive( xControlMessageBuffer,
\r
291 &xUpdatedMessageBuffer,
\r
292 sizeof( xUpdatedMessageBuffer ),
\r
293 mbaDONT_BLOCK ) == sizeof( xUpdatedMessageBuffer ) )
\r
295 /* Call the API function that sends a notification to any task that is
\r
296 blocked on the xUpdatedMessageBuffer message buffer waiting for data to
\r
298 xMessageBufferSendCompletedFromISR( xUpdatedMessageBuffer, &xHigherPriorityTaskWoken );
\r
301 /* Normal FreeRTOS yield from interrupt semantics, where
\r
302 xHigherPriorityTaskWoken is initialzed to pdFALSE and will then get set to
\r
303 pdTRUE if the interrupt safe API unblocks a task that has a priority above
\r
304 that of the currently executing task. */
\r
305 portYIELD_FROM_ISR( xHigherPriorityTaskWoken );
\r
307 /*-----------------------------------------------------------*/
\r
309 BaseType_t xAreMessageBufferAMPTasksStillRunning( void )
\r
311 static uint32_t ulLastCycleCounters[ mbaNUMBER_OF_CORE_B_TASKS ] = { 0 };
\r
314 /* Called by the check task to determine the health status of the tasks
\r
315 implemented in this demo. */
\r
316 for( x = 0; x < mbaNUMBER_OF_CORE_B_TASKS; x++ )
\r
318 if( ulLastCycleCounters[ x ] == ulCycleCounters[ x ] )
\r
320 xDemoStatus = pdFAIL;
\r
324 ulLastCycleCounters[ x ] = ulCycleCounters[ x ];
\r
328 return xDemoStatus;
\r