| /* | |
| * FreeRTOS Kernel V10.0.1 | |
| * 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. | |
| * | |
| * 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! | |
| */ | |
| /* | |
| * This is a simple example that creates two tasks and one queue. One task | |
| * periodically sends a value to the other, which then prints out a message. | |
| * Normally such a simple example would toggle an LED, so the message that is | |
| * printed out is "toggle". | |
| * | |
| * The demo configures the kernel to be as simple as possible; FreeRTOSConfig.h | |
| * excludes most features, including dynamic memory allocation. | |
| */ | |
| /* Microchip includes. */ | |
| #include "common.h" | |
| /* Scheduler includes. */ | |
| #include "FreeRTOS.h" | |
| #include "task.h" | |
| #include "queue.h" | |
| /* Priorities at which the tasks are created. */ | |
| #define mainQUEUE_RECEIVE_TASK_PRIORITY ( tskIDLE_PRIORITY + 2 ) | |
| #define mainQUEUE_SEND_TASK_PRIORITY ( tskIDLE_PRIORITY + 1 ) | |
| /* The rate at which data is sent to the queue. The 200ms value is converted | |
| to ticks using the portTICK_PERIOD_MS constant. */ | |
| #define mainQUEUE_SEND_FREQUENCY_MS ( pdMS_TO_TICKS( 1000UL ) ) | |
| /* The number of items the queue can hold. This is 1 as the receive task | |
| will remove items as they are added, meaning the send task should always find | |
| the queue empty. */ | |
| #define mainQUEUE_LENGTH_IN_ITEMS ( 1 ) | |
| /*-----------------------------------------------------------*/ | |
| /* | |
| * Configures the clocks ready to run the demo. | |
| */ | |
| static void prvSetupHardware( void ); | |
| /* | |
| * Simple routine to print a string to ITM for viewing in the Keil serial debug | |
| * viewer. | |
| */ | |
| static void prvITMPrintString( const char *pcString ); | |
| /* | |
| * The tasks as described in the comments at the top of this file. | |
| */ | |
| static void prvQueueReceiveTask( void *pvParameters ); | |
| static void prvQueueSendTask( void *pvParameters ); | |
| /*-----------------------------------------------------------*/ | |
| /* configSUPPORT_STATIC_ALLOCATION is 1 and configSUPPORT_DYNAMIC_ALLOCATION is | |
| 0 so the queue structure and the queue storage area can only be statically | |
| allocated. See http://TBD for more information. | |
| The queue storage area is dimensioned to hold just one 32-bit value. */ | |
| static StaticQueue_t xStaticQueue; | |
| static uint8_t ucQueueStorageArea[ mainQUEUE_LENGTH_IN_ITEMS * sizeof( uint32_t ) ]; | |
| /* Holds the handle of the created queue. */ | |
| static QueueHandle_t xQueue = NULL; | |
| /* configSUPPORT_STATIC_ALLOCATION is 1 and configSUPPORT_DYNAMIC_ALLOCATION is | |
| 0 so the task structure and the stacks used by the tasks can only be statically | |
| allocated. See http://TBD for more information. */ | |
| StaticTask_t xRxTCBBuffer, xTxTCBBuffer; | |
| static StackType_t uxRxStackBuffer[ configMINIMAL_STACK_SIZE ], uxTxStackBuffer[ configMINIMAL_STACK_SIZE ]; | |
| /*-----------------------------------------------------------*/ | |
| int main( void ) | |
| { | |
| /* Set up the hardware ready to run the demo. */ | |
| prvSetupHardware(); | |
| prvITMPrintString( "Starting\r\n" ); | |
| /* Create the queue. xQueueCreateStatic() has two more parameters than the | |
| xQueueCreate() function. The first new parameter is a pointer to the | |
| pre-allocated queue storage area. The second new parameter is a pointer to | |
| the StaticQueue_t structure that will hold the queue state information in | |
| an anonymous way. */ | |
| xQueue = xQueueCreateStatic( mainQUEUE_LENGTH_IN_ITEMS, /* The maximum number of items the queue can hold. */ | |
| sizeof( uint32_t ), /* The size of each item. */ | |
| ucQueueStorageArea, /* The buffer used to hold items within the queue. */ | |
| &xStaticQueue ); /* The static queue structure that will hold the state of the queue. */ | |
| /* Create the two tasks as described in the comments at the top of this | |
| file. */ | |
| xTaskCreateStatic( prvQueueReceiveTask, /* Function that implements the task. */ | |
| "Rx", /* Human readable name for the task. */ | |
| configMINIMAL_STACK_SIZE, /* Task's stack size, in words (not bytes!). */ | |
| NULL, /* Parameter to pass into the task. */ | |
| mainQUEUE_RECEIVE_TASK_PRIORITY,/* The priority of the task. */ | |
| &( uxRxStackBuffer[ 0 ] ), /* The buffer to use as the task's stack. */ | |
| &xRxTCBBuffer ); /* The variable that will hold that task's TCB. */ | |
| xTaskCreateStatic( prvQueueSendTask, /* Function that implements the task. */ | |
| "Tx", /* Human readable name for the task. */ | |
| configMINIMAL_STACK_SIZE, /* Task's stack size, in words (not bytes!). */ | |
| NULL, /* Parameter to pass into the task. */ | |
| mainQUEUE_SEND_TASK_PRIORITY, /* The priority of the task. */ | |
| &( uxTxStackBuffer[ 0 ] ), /* The buffer to use as the task's stack. */ | |
| &xTxTCBBuffer ); /* The variable that will hold that task's TCB. */ | |
| /* Start the scheduler. */ | |
| vTaskStartScheduler(); | |
| /* If dynamic memory allocation was used then the following code line would | |
| be reached if there was insufficient heap memory available to create either | |
| the timer or idle tasks. As this project is using static memory allocation | |
| then the following line should never be reached. */ | |
| for( ;; ); | |
| } | |
| /*-----------------------------------------------------------*/ | |
| static void prvQueueSendTask( void *pvParameters ) | |
| { | |
| TickType_t xNextWakeTime; | |
| const unsigned long ulValueToSend = 100UL; | |
| /* Initialise xNextWakeTime - this only needs to be done once. */ | |
| xNextWakeTime = xTaskGetTickCount(); | |
| for( ;; ) | |
| { | |
| /* Place this task in the blocked state until it is time to run again. | |
| The block time is specified in ticks, the constant used converts ticks | |
| to ms. While in the Blocked state this task will not consume any CPU | |
| time. */ | |
| vTaskDelayUntil( &xNextWakeTime, mainQUEUE_SEND_FREQUENCY_MS ); | |
| /* Send to the queue - causing the queue receive task to unblock and | |
| toggle the LED. 0 is used as the block time so the sending operation | |
| will not block - it shouldn't need to block as the queue should always | |
| be empty at this point in the code. */ | |
| xQueueSend( xQueue, &ulValueToSend, 0U ); | |
| } | |
| } | |
| /*-----------------------------------------------------------*/ | |
| static void prvQueueReceiveTask( void *pvParameters ) | |
| { | |
| unsigned long ulReceivedValue; | |
| for( ;; ) | |
| { | |
| /* Wait until something arrives in the queue - this task will block | |
| indefinitely provided INCLUDE_vTaskSuspend is set to 1 in | |
| FreeRTOSConfig.h. */ | |
| xQueueReceive( xQueue, &ulReceivedValue, portMAX_DELAY ); | |
| /* To get here something must have been received from the queue, but | |
| is it the expected value? If it is, toggle the LED. */ | |
| if( ulReceivedValue == 100UL ) | |
| { | |
| /* Output a string in lieu of using an LED. */ | |
| prvITMPrintString( "Toggle!\r\n" ); | |
| } | |
| } | |
| } | |
| /*-----------------------------------------------------------*/ | |
| static void prvSetupHardware( void ) | |
| { | |
| SystemInit(); | |
| SystemCoreClockUpdate(); | |
| } | |
| /*-----------------------------------------------------------*/ | |
| void vApplicationStackOverflowHook( TaskHandle_t pxTask, char *pcTaskName ) | |
| { | |
| /* If configCHECK_FOR_STACK_OVERFLOW is set to either 1 or 2 then this | |
| function will automatically get called if a task overflows its stack. */ | |
| ( void ) pxTask; | |
| ( void ) pcTaskName; | |
| for( ;; ); | |
| } | |
| /*-----------------------------------------------------------*/ | |
| /* configUSE_STATIC_ALLOCATION is set to 1, so the application must provide an | |
| implementation of vApplicationGetIdleTaskMemory() to provide the memory that is | |
| used by the Idle task. */ | |
| void vApplicationGetIdleTaskMemory( StaticTask_t **ppxIdleTaskTCBBuffer, StackType_t **ppxIdleTaskStackBuffer, uint32_t *pulIdleTaskStackSize ) | |
| { | |
| /* If the buffers to be provided to the Idle task are declared inside this | |
| function then they must be declared static - otherwise they will be allocated on | |
| the stack and so not exists after this function exits. */ | |
| static StaticTask_t xIdleTaskTCB; | |
| static StackType_t uxIdleTaskStack[ configMINIMAL_STACK_SIZE ]; | |
| /* Pass out a pointer to the StaticTask_t structure in which the Idle task's | |
| state will be stored. */ | |
| *ppxIdleTaskTCBBuffer = &xIdleTaskTCB; | |
| /* Pass out the array that will be used as the Idle task's stack. */ | |
| *ppxIdleTaskStackBuffer = uxIdleTaskStack; | |
| /* Pass out the size of the array pointed to by *ppxIdleTaskStackBuffer. | |
| Note that, as the array is necessarily of type StackType_t, | |
| configMINIMAL_STACK_SIZE is specified in words, not bytes. */ | |
| *pulIdleTaskStackSize = configMINIMAL_STACK_SIZE; | |
| } | |
| /*-----------------------------------------------------------*/ | |
| /* configUSE_STATIC_ALLOCATION and configUSE_TIMERS are both set to 1, so the | |
| application must provide an implementation of vApplicationGetTimerTaskMemory() | |
| to provide the memory that is used by the Timer service task. */ | |
| void vApplicationGetTimerTaskMemory( StaticTask_t **ppxTimerTaskTCBBuffer, StackType_t **ppxTimerTaskStackBuffer, uint32_t *pulTimerTaskStackSize ) | |
| { | |
| /* If the buffers to be provided to the Timer task are declared inside this | |
| function then they must be declared static - otherwise they will be allocated on | |
| the stack and so not exists after this function exits. */ | |
| static StaticTask_t xTimerTaskTCB; | |
| static StackType_t uxTimerTaskStack[ configTIMER_TASK_STACK_DEPTH ]; | |
| /* Pass out a pointer to the StaticTask_t structure in which the Timer | |
| task's state will be stored. */ | |
| *ppxTimerTaskTCBBuffer = &xTimerTaskTCB; | |
| /* Pass out the array that will be used as the Timer task's stack. */ | |
| *ppxTimerTaskStackBuffer = uxTimerTaskStack; | |
| /* Pass out the size of the array pointed to by *ppxTimerTaskStackBuffer. | |
| Note that, as the array is necessarily of type StackType_t, | |
| configMINIMAL_STACK_SIZE is specified in words, not bytes. */ | |
| *pulTimerTaskStackSize = configTIMER_TASK_STACK_DEPTH; | |
| } | |
| /*-----------------------------------------------------------*/ | |
| static void prvITMPrintString( const char *pcString ) | |
| { | |
| while( *pcString != 0x00 ) | |
| { | |
| ITM_SendChar( *pcString ); | |
| pcString++; | |
| } | |
| } | |
| /*-----------------------------------------------------------*/ | |