]> git.sur5r.net Git - freertos/blobdiff - FreeRTOS/Demo/Common/Minimal/MessageBufferAMP.c
Update to MIT licensed FreeRTOS V10.0.0 - see https://www.freertos.org/History.txt
[freertos] / FreeRTOS / Demo / Common / Minimal / MessageBufferAMP.c
diff --git a/FreeRTOS/Demo/Common/Minimal/MessageBufferAMP.c b/FreeRTOS/Demo/Common/Minimal/MessageBufferAMP.c
new file mode 100644 (file)
index 0000000..a73e482
--- /dev/null
@@ -0,0 +1,330 @@
+/*\r
+ * FreeRTOS Kernel V10.0.0\r
+ * Copyright (C) 2017 Amazon.com, Inc. or its affiliates.  All Rights Reserved.\r
+ *\r
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of\r
+ * this software and associated documentation files (the "Software"), to deal in\r
+ * the Software without restriction, including without limitation the rights to\r
+ * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of\r
+ * the Software, and to permit persons to whom the Software is furnished to do so,\r
+ * subject to the following conditions:\r
+ *\r
+ * The above copyright notice and this permission notice shall be included in all\r
+ * copies or substantial portions of the Software. If you wish to use our Amazon\r
+ * FreeRTOS name, please do so in a fair use way that does not cause confusion.\r
+ *\r
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\r
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS\r
+ * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR\r
+ * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER\r
+ * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\r
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\r
+ *\r
+ * http://www.FreeRTOS.org\r
+ * http://aws.amazon.com/freertos\r
+ *\r
+ * 1 tab == 4 spaces!\r
+ */\r
+\r
+/*\r
+ * An example that mimics a message buffer being used to pass data from one core\r
+ * to another.  The core that sends the data is referred to as core A.  The core\r
+ * that receives the data is referred to as core B.  The task implemented by\r
+ * prvCoreATask() runs on core A.  Two instances of the task implemented by\r
+ * prvCoreBTasks() run on core B.  prvCoreATask() sends messages via message\r
+ * buffers to both instances of prvCoreBTasks(), one message buffer per channel.\r
+ * A third message buffer is used to pass the handle of the message buffer\r
+ * written to by core A to an interrupt service routine that is triggered by\r
+ * core A but executes on core B.\r
+ *\r
+ * The example relies on the FreeRTOS provided default implementation of\r
+ * sbSEND_COMPLETED() being overridden by an implementation in FreeRTOSConfig.h\r
+ * that writes the handle of the message buffer that contains data into the\r
+ * control message buffer, then generates an interrupt in core B.  The necessary\r
+ * implementation is provided in this file and can be enabled by adding the\r
+ * following to FreeRTOSConfig.h:\r
+ *\r
+ * #define sbSEND_COMPLETED( pxStreamBuffer ) vGenerateCoreBInterrupt( pxStreamBuffer )\r
+ *\r
+ * Core to core communication via message buffer requires the message buffers\r
+ * to be at an address known to both cores within shared memory.\r
+ *\r
+ * Note that, while this example uses three message buffers, the same\r
+ * functionality can be implemented using a single message buffer by using the\r
+ * same design pattern described on the link below for queues, but using message\r
+ * buffers instead.  It is actually simpler with a message buffer as variable\r
+ * length data can be written into the message buffer directly:\r
+ * http://www.freertos.org/Pend-on-multiple-rtos-objects.html#alternative_design_pattern\r
+ */\r
+\r
+/* Standard includes. */\r
+#include "stdio.h"\r
+#include "string.h"\r
+\r
+/* FreeRTOS includes. */\r
+#include "FreeRTOS.h"\r
+#include "task.h"\r
+#include "message_buffer.h"\r
+\r
+/* Demo app includes. */\r
+#include "MessageBufferAMP.h"\r
+\r
+/* Enough for 3 4 byte pointers, including the additional 4 bytes per message\r
+overhead of message buffers. */\r
+#define mbaCONTROL_MESSAGE_BUFFER_SIZE ( 24 )\r
+\r
+/* Enough four 4 8 byte strings, plus the additional 4 bytes per message\r
+overhead of message buffers. */\r
+#define mbaTASK_MESSAGE_BUFFER_SIZE ( 60 )\r
+\r
+/* The number of instances of prvCoreBTasks that are created. */\r
+#define mbaNUMBER_OF_CORE_B_TASKS      2\r
+\r
+/* A block time of 0 simply means, don't block. */\r
+#define mbaDONT_BLOCK                          0\r
+\r
+/* Macro that mimics an interrupt service routine executing by simply calling\r
+the routine inline. */\r
+#define mbaGENERATE_CORE_B_INTERRUPT() prvCoreBInterruptHandler()\r
+\r
+/*-----------------------------------------------------------*/\r
+\r
+/*\r
+ * Implementation of the task that, on a real dual core device, would run on\r
+ * core A and send message to tasks running on core B.\r
+ */\r
+static void prvCoreATask( void *pvParameters );\r
+\r
+/*\r
+ * Implementation of the task that, on a real dual core device, would run on\r
+ * core B and receive message from core A.  The demo creates two instances of\r
+ * this task.\r
+ */\r
+static void prvCoreBTasks( void *pvParameters );\r
+\r
+/*\r
+ * The function that, on a real dual core device, would handle inter-core\r
+ * interrupts, but in this case is just called inline.\r
+ */\r
+static void prvCoreBInterruptHandler( void );\r
+\r
+/*-----------------------------------------------------------*/\r
+\r
+/* The message buffers used to pass data from core A to core B. */\r
+static MessageBufferHandle_t xCoreBMessageBuffers[ mbaNUMBER_OF_CORE_B_TASKS ];\r
+\r
+/* The control message buffer.  This is used to pass the handle of the message\r
+message buffer that holds application data into the core to core interrupt\r
+service routine. */\r
+static MessageBufferHandle_t xControlMessageBuffer;\r
+\r
+/* Counters used to indicate to the check that the tasks are still executing. */\r
+static uint32_t ulCycleCounters[ mbaNUMBER_OF_CORE_B_TASKS ];\r
+\r
+/* Set to pdFALSE if any errors are detected.  Used to inform the check task\r
+that something might be wrong. */\r
+BaseType_t xDemoStatus = pdPASS;\r
+\r
+/*-----------------------------------------------------------*/\r
+\r
+void vStartMessageBufferAMPTasks( void )\r
+{\r
+BaseType_t x;\r
+\r
+       xControlMessageBuffer = xMessageBufferCreate( mbaCONTROL_MESSAGE_BUFFER_SIZE );\r
+\r
+       xTaskCreate( prvCoreATask,                              /* The function that implements the task. */\r
+                                "AMPCoreA",                            /* Human readable name for the task. */\r
+                                configMINIMAL_STACK_SIZE,      /* Stack size (in words!). */\r
+                                NULL,                                          /* Task parameter is not used. */\r
+                                tskIDLE_PRIORITY,                      /* The priority at which the task is created. */\r
+                                NULL );                                        /* No use for the task handle. */\r
+\r
+       for( x = 0; x < mbaNUMBER_OF_CORE_B_TASKS; x++ )\r
+       {\r
+               xCoreBMessageBuffers[ x ] = xMessageBufferCreate( mbaTASK_MESSAGE_BUFFER_SIZE );\r
+               configASSERT( xCoreBMessageBuffers[ x ] );\r
+\r
+               /* Pass the loop counter into the created task using the task's\r
+               parameter.  The task then uses the value as an index into the\r
+               ulCycleCounters and xCoreBMessageBuffers arrays. */\r
+               xTaskCreate( prvCoreBTasks,\r
+                                        "AMPCoreB1",\r
+                                        configMINIMAL_STACK_SIZE,\r
+                                        ( void * ) x,\r
+                                        tskIDLE_PRIORITY + 1,\r
+                                        NULL );\r
+       }\r
+}\r
+/*-----------------------------------------------------------*/\r
+\r
+static void prvCoreATask( void *pvParameters )\r
+{\r
+BaseType_t x;\r
+uint32_t ulNextValue = 0;\r
+const TickType_t xDelay = pdMS_TO_TICKS( 250 );\r
+char cString[ 15 ]; /* At least large enough to hold "4294967295\0" (0xffffffff). */\r
+\r
+       /* Remove warning about unused parameters. */\r
+       ( void ) pvParameters;\r
+\r
+       for( ;; )\r
+       {\r
+               /* Create the next string to send.  The value is incremented on each\r
+               loop iteration, and the length of the string changes as the number of\r
+               digits in the value increases. */\r
+               sprintf( cString, "%lu", ( unsigned long ) ulNextValue );\r
+\r
+               /* Send the value from this (pseudo) Core A to the tasks on the (pseudo)\r
+               Core B via the message buffers.  This will result in sbSEND_COMPLETED()\r
+               being executed, which in turn will write the handle of the message\r
+               buffer written to into xControlMessageBuffer then generate an interrupt\r
+               in core B. */\r
+               for( x = 0; x < mbaNUMBER_OF_CORE_B_TASKS; x++ )\r
+               {\r
+                       xMessageBufferSend( /* The message buffer to write to. */\r
+                                                               xCoreBMessageBuffers[ x ],\r
+                                                               /* The source of the data to send. */\r
+                                                               ( void * ) cString,\r
+                                                               /* The length of the data to send. */\r
+                                                               strlen( cString ),\r
+                                                               /* The block time, should the buffer be full. */\r
+                                                               mbaDONT_BLOCK );\r
+               }\r
+\r
+               /* Delay before repeating with a different and potentially different\r
+               length string. */\r
+               vTaskDelay( xDelay );\r
+               ulNextValue++;\r
+       }\r
+}\r
+/*-----------------------------------------------------------*/\r
+\r
+static void prvCoreBTasks( void *pvParameters )\r
+{\r
+BaseType_t x;\r
+size_t xReceivedBytes;\r
+uint32_t ulNextValue = 0;\r
+char cExpectedString[ 15 ]; /* At least large enough to hold "4294967295\0" (0xffffffff). */\r
+char cReceivedString[ 15 ];\r
+\r
+       /* The index into the xCoreBMessageBuffers and ulLoopCounter arrays is\r
+       passed into this task using the task's parameter. */\r
+       x = ( BaseType_t ) pvParameters;\r
+       configASSERT( x < mbaNUMBER_OF_CORE_B_TASKS );\r
+\r
+       for( ;; )\r
+       {\r
+               /* Create the string that is expected to be received this time round. */\r
+               sprintf( cExpectedString, "%lu", ( unsigned long ) ulNextValue );\r
+\r
+               /* Wait to receive the next message from core A. */\r
+               memset( cReceivedString, 0x00, sizeof( cReceivedString ) );\r
+               xReceivedBytes = xMessageBufferReceive( /* The message buffer to receive from. */\r
+                                                                                               xCoreBMessageBuffers[ x ],\r
+                                                                                               /* Location to store received data. */\r
+                                                                                               cReceivedString,\r
+                                                                                               /* Maximum number of bytes to receive. */\r
+                                                                                               sizeof( cReceivedString ),\r
+                                                                                               /* Ticks to wait if buffer is empty. */\r
+                                                                                               portMAX_DELAY );\r
+\r
+               /* Check the number of bytes received was as expected. */\r
+               configASSERT( xReceivedBytes == strlen( cExpectedString ) );\r
+\r
+               /* If the received string matches that expected then increment the loop\r
+               counter so the check task knows this task is still running. */\r
+               if( strcmp( cReceivedString, cExpectedString ) == 0 )\r
+               {\r
+                       ( ulCycleCounters[ x ] )++;\r
+               }\r
+               else\r
+               {\r
+                       xDemoStatus = pdFAIL;\r
+               }\r
+\r
+               /* Expect the next string in sequence the next time around. */\r
+               ulNextValue++;\r
+       }\r
+}\r
+/*-----------------------------------------------------------*/\r
+\r
+/* Called by the reimplementation of sbSEND_COMPLETED(), which can be defined\r
+as follows in FreeRTOSConfig.h:\r
+#define sbSEND_COMPLETED( pxStreamBuffer ) vGenerateCoreBInterrupt( pxStreamBuffer )\r
+*/\r
+void vGenerateCoreBInterrupt( void * xUpdatedMessageBuffer )\r
+{\r
+MessageBufferHandle_t xUpdatedBuffer = ( MessageBufferHandle_t ) xUpdatedMessageBuffer;\r
+\r
+       /* If sbSEND_COMPLETED() has been implemented as above, then this function\r
+       is called from within xMessageBufferSend().  As this function also calls\r
+       xMessageBufferSend() itself it is necessary to guard against a recursive\r
+       call.  If the message buffer just updated is the message buffer written to\r
+       by this function, then this is a recursive call, and the function can just\r
+       exit without taking further action. */\r
+       if( xUpdatedBuffer != xControlMessageBuffer )\r
+       {\r
+               /* Use xControlMessageBuffer to pass the handle of the message buffer\r
+               written to by core A to the interrupt handler about to be generated in\r
+               core B. */\r
+               xMessageBufferSend( xControlMessageBuffer, &xUpdatedBuffer, sizeof( xUpdatedBuffer ), mbaDONT_BLOCK );\r
+\r
+               /* This is where the interrupt would be generated.  In this case it is\r
+               not a genuine interrupt handler that executes, just a standard function\r
+               call. */\r
+               mbaGENERATE_CORE_B_INTERRUPT();\r
+       }\r
+}\r
+/*-----------------------------------------------------------*/\r
+\r
+/* Handler for the interrupts that are triggered on core A but execute on core\r
+B. */\r
+static void prvCoreBInterruptHandler( void )\r
+{\r
+MessageBufferHandle_t xUpdatedMessageBuffer;\r
+BaseType_t xHigherPriorityTaskWoken = pdFALSE;\r
+\r
+       /* xControlMessageBuffer contains the handle of the message buffer that\r
+       contains data. */\r
+       if( xMessageBufferReceive( xControlMessageBuffer,\r
+                                                          &xUpdatedMessageBuffer,\r
+                                                          sizeof( xUpdatedMessageBuffer ),\r
+                                                          mbaDONT_BLOCK ) == sizeof( xUpdatedMessageBuffer ) )\r
+       {\r
+               /* Call the API function that sends a notification to any task that is\r
+               blocked on the xUpdatedMessageBuffer message buffer waiting for data to\r
+               arrive. */\r
+               xMessageBufferSendCompletedFromISR( xUpdatedMessageBuffer, &xHigherPriorityTaskWoken );\r
+       }\r
+\r
+       /* Normal FreeRTOS yield from interrupt semantics, where\r
+       xHigherPriorityTaskWoken is initialzed to pdFALSE and will then get set to\r
+       pdTRUE if the interrupt safe API unblocks a task that has a priority above\r
+       that of the currently executing task. */\r
+       portYIELD_FROM_ISR( xHigherPriorityTaskWoken );\r
+}\r
+/*-----------------------------------------------------------*/\r
+\r
+BaseType_t xAreMessageBufferAMPTasksStillRunning( void )\r
+{\r
+static uint32_t ulLastCycleCounters[ mbaNUMBER_OF_CORE_B_TASKS ] = { 0 };\r
+BaseType_t x;\r
+\r
+       /* Called by the check task to determine the health status of the tasks\r
+       implemented in this demo. */\r
+       for( x = 0; x < mbaNUMBER_OF_CORE_B_TASKS; x++ )\r
+       {\r
+               if( ulLastCycleCounters[ x ] == ulCycleCounters[ x ] )\r
+               {\r
+                       xDemoStatus = pdFAIL;\r
+               }\r
+               else\r
+               {\r
+                       ulLastCycleCounters[ x ] = ulCycleCounters[ x ];\r
+               }\r
+       }\r
+\r
+       return xDemoStatus;\r
+}\r
+\r