licensing and training services.\r
*/\r
\r
+/*\r
+ * The documentation page for this demo available on http://www.FreeRTOS.org\r
+ * documents the hardware configuration required to run this demo. It also\r
+ * provides more information on the expected demo application behaviour.\r
+ *\r
+ * main() creates all the demo application tasks, then starts the scheduler.\r
+ * A lot of the created tasks are from the pool of "standard demo" tasks. The\r
+ * web documentation provides more details of the standard demo application\r
+ * tasks, which provide no particular functionality but do provide a good\r
+ * example of how to use the FreeRTOS API.\r
+ *\r
+ * In addition to the standard demo tasks, the following tasks, interrupts and\r
+ * tests are defined and/or created within this file:\r
+ *\r
+ * "LCD" task - The LCD task is a 'gatekeeper' task. It is the only task that\r
+ * is permitted to access the LCD and therefore ensures access to the LCD is\r
+ * always serialised and there are no mutual exclusion issues. When a task or\r
+ * an interrupt wants to write to the LCD, it does not access the LCD directly\r
+ * but instead sends the message to the LCD task. The LCD task then performs\r
+ * the actual LCD output. This mechanism also allows interrupts to, in effect,\r
+ * write to the LCD by sending messages to the LCD task.\r
+ *\r
+ * The LCD task is also a demonstration of a controller task design pattern.\r
+ * Some tasks do not actually send a string to the LCD task directly, but\r
+ * instead send a command that is interpreted by the LCD task. In a normal\r
+ * application these commands can be control values or set points, in this\r
+ * simple example the commands just result in messages being displayed on the\r
+ * LCD.\r
+ *\r
+ * "Button Poll" task - This task polls the state of the 'up' key on the\r
+ * joystick input device. It uses the vTaskDelay() API function to control\r
+ * the poll rate to ensure debouncing is not necessary and that the task does\r
+ * not use all the available CPU processing time.\r
+ *\r
+ * Button Interrupt and run time stats display - The select button on the\r
+ * joystick input device is configured to generate an external interrupt. The\r
+ * handler for this interrupt sends a message to LCD task, which interprets the\r
+ * message to mean, firstly write a message to the LCD, and secondly, generate\r
+ * a table of run time statistics. The run time statistics are displayed as a\r
+ * table that contains information on how much processing time each task has\r
+ * been allocated since the application started to execute. This information\r
+ * is provided both as an absolute time, and as a percentage of the total run\r
+ * time. The information is displayed in the terminal IO window of the IAR\r
+ * embedded workbench. The online documentation for this demo shows a screen\r
+ * shot demonstrating where the run time stats can be viewed.\r
+ *\r
+ * Idle Hook - The idle hook is a function that is called on each iteration of\r
+ * the idle task. In this case it is used to place the processor into a low\r
+ * power mode. Note however that this application is implemented using standard\r
+ * components, and is therefore not optimised for low power operation. Lower\r
+ * power consumption would be achieved by converting polling tasks into event\r
+ * driven tasks, and slowing the tick interrupt frequency.\r
+ *\r
+ * "Check" function called from the tick hook - The tick hook is called during\r
+ * each tick interrupt. It is called from an interrupt context so must execute\r
+ * quickly, not attempt to block, and not call any FreeRTOS API functions that\r
+ * do not end in "FromISR". In this case the tick hook executes a 'check'\r
+ * function. This only executes every five seconds. Its main function is to\r
+ * check that all the standard demo tasks are still operational. Each time it\r
+ * executes it sends a status code to the LCD task. The LCD task interprets the\r
+ * code and displays an appropriate message - which will be PASS if no tasks\r
+ * have reported any errors, or a message stating which task has reported an\r
+ * error.\r
+*/\r
+\r
/* Standard includes. */\r
#include <stdio.h>\r
\r
#include "comtest2.h"\r
#include "GenQTest.h"\r
\r
-/* ST driver includes. */\r
-#include "stm32l1xx_usart.h"\r
-\r
/* Eval board includes. */\r
#include "stm32_eval.h"\r
#include "stm32l152_eval_lcd.h"\r
\r
+/* The priorities assigned to the tasks. */\r
#define mainFLASH_TASK_PRIORITY ( tskIDLE_PRIORITY + 1 )\r
#define mainLCD_TASK_PRIORITY ( tskIDLE_PRIORITY + 1 )\r
#define mainCOM_TEST_PRIORITY ( tskIDLE_PRIORITY + 2 )\r
#define mainGENERIC_QUEUE_TEST_PRIORITY ( tskIDLE_PRIORITY )\r
\r
-#define mainLCD_TASK_STACK_SIZE ( configMINIMAL_STACK_SIZE * 2 )\r
-\r
+/* The length of the queue (the number of items the queue can hold) that is used\r
+to send messages from tasks and interrupts the the LCD task. */\r
#define mainQUEUE_LENGTH ( 5 )\r
\r
+/* Codes sent within message to the LCD task so the LCD task can interrupt\r
+exactly what the message it just received was. These are sent in the\r
+cMessageID member of the message structure (defined below). */\r
#define mainMESSAGE_BUTTON_UP ( 1 )\r
-#define mainMESSAGE_BUTTON_DOWN ( 2 )\r
-#define mainMESSAGE_BUTTON_LEFT ( 3 )\r
-#define mainMESSAGE_BUTTON_RIGHT ( 4 )\r
-#define mainMESSAGE_BUTTON_SEL ( 5 )\r
-#define mainMESSAGE_STATUS ( 6 )\r
-\r
-#define mainERROR_DYNAMIC_TASKS ( 2 )\r
-#define mainERROR_COM_TEST ( 3 )\r
-#define mainERROR_GEN_QUEUE_TEST ( 4 )\r
+#define mainMESSAGE_BUTTON_SEL ( 2 )\r
+#define mainMESSAGE_STATUS ( 3 )\r
+\r
+/* When cMessageID member of the message sent to the LCD task is\r
+mainMESSAGE_STATUS then these definitions are sent in the lMessageValue member\r
+of the same message to indicate what the status actually is. The value 1 is not\r
+used as this is globally defined as pdPASS, and indicates that no errors have\r
+been reported (the system is running as expected). */\r
+#define mainERROR_DYNAMIC_TASKS ( pdPASS + 1 )\r
+#define mainERROR_COM_TEST ( pdPASS + 2 )\r
+#define mainERROR_GEN_QUEUE_TEST ( pdPASS + 3 )\r
\r
/* Baud rate used by the comtest tasks. */\r
-#define mainCOM_TEST_BAUD_RATE ( 9600 )\r
+#define mainCOM_TEST_BAUD_RATE ( 115200 )\r
\r
/* The LED used by the comtest tasks. See the comtest.c file for more\r
information. */\r
#define mainCOM_TEST_LED ( 3 )\r
\r
+/*-----------------------------------------------------------*/\r
\r
/*\r
* System configuration is performed prior to main() being called, this function\r
* configures the peripherals used by the demo application.\r
*/\r
static void prvSetupHardware( void );\r
+\r
+/*\r
+ * Definition of the LCD/controller task described in the comments at the top\r
+ * of this file.\r
+ */\r
static void prvLCDTask( void *pvParameters );\r
-static void vTempTask( void *pv );\r
+\r
+/*\r
+ * Definition of the button poll task described in the comments at the top of\r
+ * this file.\r
+ */\r
+static void vButtonPollTask( void *pvParameters );\r
+\r
+/*\r
+ * Converts a status message value into an appropriate string for display on\r
+ * the LCD. The string is written to pcBuffer.\r
+ */\r
static void prvGenerateStatusMessage( char *pcBuffer, long lStatusValue );\r
\r
+/*-----------------------------------------------------------*/\r
+\r
+/* The time base for the run time stats is generated by the 16 bit timer 6.\r
+Each time the timer overflows ulTIM6_OverflowCount is incremented. Therefore,\r
+when converting the total run time to a 32 bit number, the most significant two\r
+bytes are given by ulTIM6_OverflowCount and the least significant two bytes are\r
+given by the current TIM6 counter value. Care must be taken with data\r
+consistency when combining the two in case a timer overflow occurs as the\r
+value is being read. */\r
unsigned long ulTIM6_OverflowCount = 0UL;\r
\r
+/* The handle of the queue used to send messages from tasks and interrupts to\r
+the LCD task. */\r
static xQueueHandle xLCDQueue = NULL;\r
\r
+/* The definition of each message sent from tasks and interrupts to the LCD\r
+task. */\r
typedef struct\r
{\r
- char cMessageID;\r
- long lMessageValue;\r
+ char cMessageID; /* << States what the message is. */\r
+ long lMessageValue; /* << States the message value (can be an integer, string pointer, etc. depending on the value of cMessageID. */\r
} xQueueMessage;\r
\r
+/*-----------------------------------------------------------*/\r
+\r
void main( void )\r
{\r
+ /* Configure the peripherals used by this demo application. This includes\r
+ configuring the joystick input select button to generate interrupts. */\r
prvSetupHardware();\r
\r
/* Create the queue used by tasks and interrupts to send strings to the LCD\r
task. */\r
xLCDQueue = xQueueCreate( mainQUEUE_LENGTH, sizeof( xQueueMessage ) );\r
\r
+ /* If the queue could not be created then don't create any tasks that might\r
+ attempt to use the queue. */\r
if( xLCDQueue != NULL )\r
{\r
+ /* Add the created queue to the queue registry so it can be viewed in\r
+ the IAR FreeRTOS state viewer plug-in. */\r
vQueueAddToRegistry( xLCDQueue, "LCDQueue" );\r
- xTaskCreate( prvLCDTask, ( signed char * ) "LCD", mainLCD_TASK_STACK_SIZE, NULL, mainLCD_TASK_PRIORITY, NULL );\r
- xTaskCreate( vTempTask, ( signed char * ) "Temp", configMINIMAL_STACK_SIZE, NULL, tskIDLE_PRIORITY, NULL );\r
+ \r
+ /* Create the LCD and button poll tasks, as described at the top of this\r
+ file. */\r
+ xTaskCreate( prvLCDTask, ( signed char * ) "LCD", configMINIMAL_STACK_SIZE, NULL, mainLCD_TASK_PRIORITY, NULL );\r
+ xTaskCreate( vButtonPollTask, ( signed char * ) "Temp", configMINIMAL_STACK_SIZE, NULL, tskIDLE_PRIORITY, NULL );\r
+ \r
+ /* Create a subset of the standard demo tasks. */\r
vStartDynamicPriorityTasks();\r
vStartLEDFlashTasks( mainFLASH_TASK_PRIORITY );\r
vAltStartComTestTasks( mainCOM_TEST_PRIORITY, mainCOM_TEST_BAUD_RATE, mainCOM_TEST_LED );\r
vStartGenericQueueTasks( mainGENERIC_QUEUE_TEST_PRIORITY );\r
\r
+ /* Start the scheduler. */\r
vTaskStartScheduler();\r
}\r
\r
+ /* If all is well then this line will never be reached. If it is reached\r
+ then it is likely that there was insufficient (FreeRTOS) heap memory space\r
+ to create the idle task. This may have been trapped by the malloc() failed\r
+ hook function, if one is configured. */\r
for( ;; );\r
}\r
/*-----------------------------------------------------------*/\r
xQueueMessage xReceivedMessage;\r
long lLine = Line1;\r
const long lFontHeight = (((sFONT *)LCD_GetFont())->Height);\r
+\r
+/* Buffer into which strings are formatted and placed ready for display on the\r
+LCD. Note this is a static variable to prevent it being allocated on the task\r
+stack, which is too small to hold such a variable. The stack size is configured\r
+when the task is created. */\r
static char cBuffer[ 512 ];\r
\r
/* This function is the only function that uses printf(). If printf() is\r
used from any other function then some sort of mutual exclusion on stdout\r
- will be necessary. */\r
-\r
+ will be necessary.\r
+ \r
+ This is also the only function that is permitted to access the LCD.\r
+ \r
+ First print out the number of bytes that remain in the FreeRTOS heap. This\r
+ can be viewed in the terminal IO window within the IAR Embedded Workbench. */\r
printf( "%d bytes of heap space remain unallocated\n", xPortGetFreeHeapSize() );\r
\r
for( ;; )\r
{\r
+ /* Wait for a message to be received. This will wait indefinitely if\r
+ INCLUDE_vTaskSuspend is set to 1 in FreeRTOSConfig.h, therefore there\r
+ is no need to check the function return value. */\r
xQueueReceive( xLCDQueue, &xReceivedMessage, portMAX_DELAY );\r
\r
+ /* Clear the LCD if the last LCD message was output to the last\r
+ available line on the LCD. */\r
if( lLine > Line9 )\r
{\r
LCD_Clear( Blue );\r
lLine = 0;\r
}\r
\r
+ /* What is this message? What does it contain? */\r
switch( xReceivedMessage.cMessageID )\r
{\r
- case mainMESSAGE_BUTTON_UP : sprintf( cBuffer, "Button up = %d", xReceivedMessage.lMessageValue );\r
- break;\r
- case mainMESSAGE_BUTTON_DOWN : sprintf( cBuffer, "Button down = %d", xReceivedMessage.lMessageValue );\r
- break;\r
- case mainMESSAGE_BUTTON_LEFT : sprintf( cBuffer, "Button left = %d", xReceivedMessage.lMessageValue );\r
- break;\r
- case mainMESSAGE_BUTTON_RIGHT : sprintf( cBuffer, "Button right = %d", xReceivedMessage.lMessageValue );\r
+ case mainMESSAGE_BUTTON_UP : /* The button poll task has just\r
+ informed this task that the up\r
+ button on the joystick input has\r
+ been pressed or released. */\r
+ sprintf( cBuffer, "Button up = %d", xReceivedMessage.lMessageValue );\r
break;\r
- case mainMESSAGE_BUTTON_SEL : printf( "\nTask\t Abs Time\t %%Time\n*****************************************" );\r
+\r
+ case mainMESSAGE_BUTTON_SEL : /* The select button interrupt\r
+ just informed this task that the\r
+ select button was pressed.\r
+ Generate a table of task run time\r
+ statistics and output this to\r
+ the terminal IO window in the IAR\r
+ embedded workbench. */\r
+ printf( "\nTask\t Abs Time\t %%Time\n*****************************************" );\r
vTaskGetRunTimeStats( ( signed char * ) cBuffer );\r
printf( cBuffer );\r
\r
- /* The select button passes its\r
- own string to print out. */\r
+ /* Also print out a message to\r
+ the LCD - in this case the\r
+ pointer to the string to print\r
+ is sent directly in the\r
+ lMessageValue member of the\r
+ message. This just demonstrates\r
+ a different communication\r
+ technique. */\r
sprintf( cBuffer, "%s", ( char * ) xReceivedMessage.lMessageValue );\r
break;\r
- case mainMESSAGE_STATUS : prvGenerateStatusMessage( cBuffer, xReceivedMessage.lMessageValue );\r
+ \r
+ case mainMESSAGE_STATUS : /* The tick interrupt hook\r
+ function has just informed this\r
+ task of the system status.\r
+ Generate a string in accordance\r
+ with the status value. */\r
+ prvGenerateStatusMessage( cBuffer, xReceivedMessage.lMessageValue );\r
break;\r
+ \r
default : sprintf( cBuffer, "Unknown message" );\r
break;\r
}\r
\r
+ /* Output the message that was placed into the cBuffer array within the\r
+ switch statement above. */\r
LCD_DisplayStringLine( lLine, ( uint8_t * ) cBuffer );\r
+ \r
+ /* Move onto the next LCD line, ready for the next iteration of this\r
+ loop. */\r
lLine += lFontHeight;\r
}\r
}\r
\r
static void prvGenerateStatusMessage( char *pcBuffer, long lStatusValue )\r
{\r
+ /* Just a utility function to convert a status value into a meaningful\r
+ string for output onto the LCD. */\r
switch( lStatusValue )\r
{\r
case pdPASS : sprintf( pcBuffer, "Task status = PASS" );\r
break;\r
case mainERROR_DYNAMIC_TASKS : sprintf( pcBuffer, "Error: Dynamic tasks" );\r
break;\r
- case mainERROR_COM_TEST : sprintf( pcBuffer, "Error: COM test" );\r
+ case mainERROR_COM_TEST : sprintf( pcBuffer, "Err: loop connected?" ); /* Error in COM test - is the Loopback connector connected? */ \r
break;\r
case mainERROR_GEN_QUEUE_TEST : sprintf( pcBuffer, "Error: Gen Q test" );\r
break;\r
\r
void EXTI9_5_IRQHandler( void )\r
{\r
+/* Define the message sent to the LCD task from this interrupt. */\r
const xQueueMessage xMessage = { mainMESSAGE_BUTTON_SEL, ( unsigned long ) "Select Interrupt!" };\r
long lHigherPriorityTaskWoken = pdFALSE;\r
\r
+ /* This is the interrupt handler for the joystick select button input.\r
+ The button has been pushed, write a message to the LCD via the LCD task. */\r
xQueueSendFromISR( xLCDQueue, &xMessage, &lHigherPriorityTaskWoken );\r
+ \r
EXTI_ClearITPendingBit( SEL_BUTTON_EXTI_LINE );\r
+ \r
+ /* If writing to xLCDQueue caused a task to unblock, and the unblocked task\r
+ has a priority equal to or above the task that this interrupt interrupted,\r
+ then lHigherPriorityTaskWoken will have been set to pdTRUE internally within\r
+ xQueuesendFromISR(), and portEND_SWITCHING_ISR() will ensure that this\r
+ interrupt returns directly to the higher priority unblocked task. */\r
portEND_SWITCHING_ISR( lHigherPriorityTaskWoken );\r
}\r
/*-----------------------------------------------------------*/\r
{\r
static unsigned long ulCounter = 0;\r
static const unsigned long ulCheckFrequency = 5000UL / portTICK_RATE_MS;\r
+long lHigherPriorityTaskWoken = pdFALSE;\r
+\r
+/* Define the status message that is sent to the LCD task. By default the\r
+status is PASS. */\r
static xQueueMessage xStatusMessage = { mainMESSAGE_STATUS, pdPASS };\r
-long lHigherPriorityTaskWoken = pdFALSE; /* Not used in this case as this is the tick hook. */\r
\r
+ /* This is called from within the tick interrupt and performs the 'check'\r
+ functionality as described in the comments at the top of this file.\r
+\r
+ Is it time to perform the 'check' functionality again? */\r
ulCounter++;\r
if( ulCounter >= ulCheckFrequency )\r
{\r
+ /* See if the standard demo tasks are executing as expected, changing\r
+ the message that is sent to the LCD task from PASS to an error code if\r
+ any tasks set reports an error. */\r
if( xAreDynamicPriorityTasksStillRunning() != pdPASS )\r
{\r
xStatusMessage.lMessageValue = mainERROR_DYNAMIC_TASKS;\r
xStatusMessage.lMessageValue = mainERROR_GEN_QUEUE_TEST;\r
}\r
\r
+ /* As this is the tick hook the lHigherPriorityTaskWoken parameter is not\r
+ needed (a context switch is going to be performed anyway), but it must\r
+ still be provided. */\r
xQueueSendFromISR( xLCDQueue, &xStatusMessage, &lHigherPriorityTaskWoken );\r
ulCounter = 0;\r
}\r
}\r
/*-----------------------------------------------------------*/\r
\r
-static void vTempTask( void *pv )\r
+static void vButtonPollTask( void *pvParameters )\r
{\r
long lLastState = pdTRUE;\r
long lState;\r
xQueueMessage xMessage;\r
\r
+ /* This tasks performs the button polling functionality as described at the\r
+ top of this file. */\r
for( ;; )\r
{\r
+ /* Check the button state. */\r
lState = STM_EVAL_PBGetState( BUTTON_UP );\r
if( lState != lLastState )\r
{\r
+ /* The state has changed, send a message to the LCD task. */\r
xMessage.cMessageID = mainMESSAGE_BUTTON_UP;\r
xMessage.lMessageValue = lState;\r
lLastState = lState;\r
xQueueSend( xLCDQueue, &xMessage, portMAX_DELAY );\r
- vTaskDelay( 10 );\r
}\r
+ \r
+ /* Block for 10 milliseconds so this task does not utilise all the CPU\r
+ time and debouncing of the button is not necessary. */\r
+ vTaskDelay( 10 / portTICK_RATE_MS );\r
}\r
}\r
/*-----------------------------------------------------------*/\r
\r
static void prvSetupHardware( void )\r
{\r
+ /* Ensure that all 4 interrupt priority bits are used as the pre-emption\r
+ priority. */\r
NVIC_PriorityGroupConfig( NVIC_PriorityGroup_4 );\r
\r
/* Initialise the LEDs. */\r
\r
/* The select button in the middle of the joystick is configured to generate\r
an interrupt. The Eval board library will configure the interrupt\r
- priority to be the lowest priority available - this is important as the\r
- interrupt service routine makes use of a FreeRTOS API function so must\r
- therefore use a priority equal to or below that set by the\r
- configMAX_SYSCALL_INTERRUPT_PRIORITY() value set in FreeRTOSConfig.h. */\r
+ priority to be the lowest priority available so the priority need not be\r
+ set here explicitly. It is important that the priority is equal to or\r
+ below that set by the configMAX_SYSCALL_INTERRUPT_PRIORITY value set in\r
+ FreeRTOSConfig.h. */\r
STM_EVAL_PBInit( BUTTON_SEL, BUTTON_MODE_EXTI );\r
\r
/* Initialize the LCD */\r
- STM32L152_LCD_Init();\r
- \r
- LCD_Clear(Blue);\r
- LCD_SetBackColor(Blue);\r
- LCD_SetTextColor(White);\r
- LCD_DisplayStringLine(Line0, " www.FreeRTOS.org");\r
+ STM32L152_LCD_Init(); \r
+ LCD_Clear( Blue );\r
+ LCD_SetBackColor( Blue );\r
+ LCD_SetTextColor( White );\r
+ LCD_DisplayStringLine( Line0, " www.FreeRTOS.org" );\r
}\r
/*-----------------------------------------------------------*/\r
\r
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;\r
NVIC_InitTypeDef NVIC_InitStructure;\r
\r
+ /* The time base for the run time stats is generated by the 16 bit timer 6.\r
+ Each time the timer overflows ulTIM6_OverflowCount is incremented.\r
+ Therefore, when converting the total run time to a 32 bit number, the most\r
+ significant two bytes are given by ulTIM6_OverflowCount and the least\r
+ significant two bytes are given by the current TIM6 counter value. Care\r
+ must be taken with data consistency when combining the two in case a timer\r
+ overflow occurs as the value is being read.\r
+ \r
+ The portCONFIGURE_TIMER_FOR_RUN_TIME_STATS() macro (in FreeRTOSConfig.h) is\r
+ defined to call this function, so the kernel will call this function\r
+ automatically at the appropriate time. */\r
+\r
/* TIM6 clock enable */\r
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM6, ENABLE);\r
\r
/* Only interrupt on overflow events. */\r
TIM6->CR1 |= TIM_CR1_URS;\r
\r
+ /* Enable the interrupt. */\r
TIM_ITConfig( TIM6, TIM_IT_Update, ENABLE );\r
\r
- /* Enable the TIM6 gloabal Interrupt */\r
+ /* Enable the TIM6 global Interrupt */\r
NVIC_InitStructure.NVIC_IRQChannel = TIM6_IRQn;\r
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = configLIBRARY_LOWEST_INTERRUPT_PRIORITY;\r
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0x00; /* Not used as 4 bits are used for the pre-emption priority. */\r
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;\r
+ NVIC_Init(&NVIC_InitStructure);\r
\r
TIM_ClearITPendingBit( TIM6, TIM_IT_Update );\r
- NVIC_Init(&NVIC_InitStructure);\r
TIM_Cmd( TIM6, ENABLE );\r
}\r
/*-----------------------------------------------------------*/\r
\r
void TIM6_IRQHandler( void )\r
{\r
+ /* Interrupt handler for TIM 6\r
+ \r
+ The time base for the run time stats is generated by the 16 bit timer 6.\r
+ Each time the timer overflows ulTIM6_OverflowCount is incremented.\r
+ Therefore, when converting the total run time to a 32 bit number, the most\r
+ significant two bytes are given by ulTIM6_OverflowCount and the least\r
+ significant two bytes are given by the current TIM6 counter value. Care\r
+ must be taken with data consistency when combining the two in case a timer\r
+ overflow occurs as the value is being read. */\r
if( TIM_GetITStatus( TIM6, TIM_IT_Update) != RESET)\r
{\r
ulTIM6_OverflowCount++;\r
( void ) pcTaskName;\r
( void ) pxTask;\r
\r
+ /* Run time stack overflow checking is performed if\r
+ configconfigCHECK_FOR_STACK_OVERFLOW is defined to 1 or 2. This hook\r
+ function is called if a stack overflow is detected. */\r
for( ;; );\r
}\r
/*-----------------------------------------------------------*/\r
\r
void vApplicationMallocFailedHook( void )\r
{\r
+ /* Called if a call to pvPortMalloc() fails because there is insufficient\r
+ free memory available in the FreeRTOS heap. pvPortMalloc() is called\r
+ internally by FreeRTOS API functions that create tasks, queues or\r
+ semaphores. */\r
for( ;; );\r
}\r
/*-----------------------------------------------------------*/\r
\r
void vApplicationIdleHook( void )\r
{\r
+ /* Called on each itteration of the idle task. In this case the idle task\r
+ just enters a low(ish) power mode. */\r
PWR_EnterSleepMode( PWR_Regulator_ON, PWR_SLEEPEntry_WFI );\r
}\r
\r