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