Tidy up STM32L low power demo and add 'comprehensive demo' option.

This commit is contained in:
Richard Barry 2013-12-10 16:20:43 +00:00
parent 5638fe28a2
commit 751103d848
8 changed files with 790 additions and 1154 deletions

View File

@ -49,7 +49,7 @@
</option>
<option>
<name>RunToEnable</name>
<state>0</state>
<state>1</state>
</option>
<option>
<name>RunToName</name>

View File

@ -39,20 +39,20 @@
<option>
<name>Input variant</name>
<version>3</version>
<state>1</state>
<state>7</state>
</option>
<option>
<name>Input description</name>
<state>Full formatting.</state>
<state>No specifier n, no float nor long long, no scan set, no assignment suppressing, without multibyte support.</state>
</option>
<option>
<name>Output variant</name>
<version>2</version>
<state>1</state>
<state>7</state>
</option>
<option>
<name>Output description</name>
<state>Full formatting.</state>
<state>No specifier a, A, no specifier n, no float nor long long, no flags.</state>
</option>
<option>
<name>GOutputBinary</name>
@ -70,16 +70,16 @@
<option>
<name>GRuntimeLibSelect</name>
<version>0</version>
<state>2</state>
<state>1</state>
</option>
<option>
<name>GRuntimeLibSelectSlave</name>
<version>0</version>
<state>2</state>
<state>1</state>
</option>
<option>
<name>RTDescription</name>
<state>Use the full configuration of the C/C++ runtime library. Full locale interface, C locale, file descriptor support, multibytes in printf and scanf, and hex floats in strtod.</state>
<state>Use the normal configuration of the C/C++ runtime library. No locale interface, C locale, no file descriptor support, no multibytes in printf and scanf, and no hex floats in strtod.</state>
</option>
<option>
<name>OGProductVersion</name>
@ -103,7 +103,7 @@
</option>
<option>
<name>GenLowLevelInterface</name>
<state>1</state>
<state>0</state>
</option>
<option>
<name>GEndianModeBE</name>
@ -133,7 +133,7 @@
</option>
<option>
<name>RTConfigPath2</name>
<state>$TOOLKIT_DIR$\INC\c\DLib_Config_Full.h</state>
<state>$TOOLKIT_DIR$\INC\c\DLib_Config_Normal.h</state>
</option>
<option>
<name>GFPUCoreSlave</name>
@ -309,6 +309,7 @@
<state>$PROJ_DIR$\ST_Code\libraries\CMSIS\Device\ST\STM32L1xx\Include</state>
<state>$PROJ_DIR$\..\..\Source\include</state>
<state>$PROJ_DIR$\..\..\Source\portable\IAR\ARM_CM3</state>
<state>$PROJ_DIR$\..\Common\include</state>
</option>
<option>
<name>CCStdIncCheck</name>
@ -645,7 +646,7 @@
</option>
<option>
<name>IlinkOutputFile</name>
<state>STM32L-Discovery.out</state>
<state>RTOSDemo.out</state>
</option>
<option>
<name>IlinkDebugInfoEnable</name>
@ -1064,6 +1065,33 @@
</file>
</group>
</group>
<group>
<name>Standard Demo Tasks</name>
<file>
<name>$PROJ_DIR$\..\Common\Minimal\BlockQ.c</name>
</file>
<file>
<name>$PROJ_DIR$\..\Common\Minimal\blocktim.c</name>
</file>
<file>
<name>$PROJ_DIR$\..\Common\Minimal\countsem.c</name>
</file>
<file>
<name>$PROJ_DIR$\..\Common\Minimal\dynamic.c</name>
</file>
<file>
<name>$PROJ_DIR$\..\Common\Minimal\GenQTest.c</name>
</file>
<file>
<name>$PROJ_DIR$\..\Common\Minimal\PollQ.c</name>
</file>
<file>
<name>$PROJ_DIR$\..\Common\Minimal\recmutex.c</name>
</file>
<file>
<name>$PROJ_DIR$\..\Common\Minimal\semtest.c</name>
</file>
</group>
<group>
<name>System</name>
<file>
@ -1088,6 +1116,12 @@
<file>
<name>$PROJ_DIR$\main.c</name>
</file>
<file>
<name>$PROJ_DIR$\main_full.c</name>
</file>
<file>
<name>$PROJ_DIR$\main_low_power.c</name>
</file>
<file>
<name>$PROJ_DIR$\stm32l1xx_it.c</name>
</file>

View File

@ -75,8 +75,8 @@
/*
* When configCREATE_LOW_POWER_DEMO is set to 1 then the tick interrupt
* is generated by the wakeup interrupt of the real time clock (RTC). The RTC
* configuration and handling functions are defined in this file.
* is generated by the TIM2 peripheral. The TIM2 configuration and handling
* functions are defined in this file.
*
* When configCREATE_LOW_POWER_DEMO is set to 0 the tick interrupt is
* generated by the standard FreeRTOS Cortex-M port layer, which uses the
@ -84,23 +84,17 @@
*/
#if configCREATE_LOW_POWER_DEMO == 1
/* The frequency at which TIM2 should run. */
/* The frequency at which TIM2 will run. */
#define lpCLOCK_INPUT_FREQUENCY ( 1000UL )
/* Constants required to pend a PendSV interrupt from the tick ISR if the
preemptive scheduler is being used. These are just standard bits and registers
within the Cortex-M core itself. */
#define portNVIC_PENDSVSET_BIT ( 1UL << 28UL )
/* STM32 register used to ensure the TIM2 clock stops when the MCU is in debug
mode. */
#define DBGMCU_APB1_FZ ( * ( ( volatile unsigned long * ) 0xE0042008 ) )
/*-----------------------------------------------------------*/
/*
* The tick interrupt is generated by the TIM2 timer. The default interrupt
* handler cannot be used (even with the TIM2 being handled from the tick hook
* function) because the default tick interrupt accesses the SysTick registers
* when configUSE_TICKLESS_IDLE set to 1. TIM2_IRQHandler() is the default name
* for the TIM2 interrupt handler.
* The tick interrupt is generated by the TIM2 timer.
*/
void TIM2_IRQHandler( void );
@ -115,15 +109,9 @@ initialisation. */
static portTickType xMaximumPossibleSuppressedTicks = 0;
/* Flag set from the tick interrupt to allow the sleep processing to know if
sleep mode was exited because of an RTC interrupt or a different interrupt. */
sleep mode was exited because of an tick interrupt or a different interrupt. */
static volatile uint32_t ulTickFlag = pdFALSE;
/* The RTC counter is stopped temporarily each time it is re-programmed. The
following variable offsets the RTC counter alarm value by the number of RTC
counts that would typically be missed while the counter was stopped to
compensate for the lost time. _RB_ Value needs calculating correctly. */
static uint32_t ulStoppedTimerCompensation = 1;//_RB_ / ( configCPU_CLOCK_HZ / configSYSTICK_CLOCK_HZ );
/*-----------------------------------------------------------*/
/* The tick interrupt handler. This is always the same other than the part that
@ -131,10 +119,13 @@ clears the interrupt, which is specific to the clock being used to generate the
tick. */
void TIM2_IRQHandler( void )
{
/* Clear the interrupt. */
TIM_ClearITPendingBit( TIM2, TIM_IT_Update );
TIM_SetAutoreload( TIM2, ( uint16_t ) ulReloadValueForOneTick );
/* Protect incrementing the tick with an interrupt safe critical section. */
/* The next block of code is from the standard FreeRTOS tick interrupt
handler. The standard handler is not called directly in case future
versions contain changes that make it no longer suitable for calling
here. */
( void ) portSET_INTERRUPT_MASK_FROM_ISR();
{
if( xTaskIncrementTick() != pdFALSE )
@ -148,39 +139,42 @@ void TIM2_IRQHandler( void )
}
portCLEAR_INTERRUPT_MASK_FROM_ISR( 0 );
/* In case this is the first tick since the MCU left a low power mode the
reload value is reset to its default. */
TIM2->ARR = ( uint16_t ) ulReloadValueForOneTick;
/* The CPU woke because of a tick. */
ulTickFlag = pdTRUE;
}
/*-----------------------------------------------------------*/
/* Override the default definition of vPortSetupTimerInterrupt() that is weakly
defined in the FreeRTOS Cortex-M3 port layer with a version that configures the
wakeup timer of the RTC to generate the tick interrupt. */
defined in the FreeRTOS Cortex-M3 port layer with a version that configures TIM2
to generate the tick interrupt. */
void vPortSetupTimerInterrupt( void )
{
NVIC_InitTypeDef NVIC_InitStructure;
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
/* Enable the TIM2 clock, which is used to generate long tickless periods
when the tickless period is finite. */
/* Enable the TIM2 clock. */
RCC_APB1PeriphClockCmd( RCC_APB1Periph_TIM2, ENABLE );
/* Ensure clock stops in debug mode. */
DBGMCU_APB1_FZ |= DBGMCU_APB1_FZ_DBG_TIM2_STOP;
/* Scale the clock so very long tickless periods can be acheived. The
SysTick is not used as even when its frequency is divided by 8 the maximum
tickless period with a system clock of 16MHz is only 8.3 seconds. Using
a prescaled clock on the 16-bit TIM2 allows a tickless period of nearly
66 seconds, albeit at low resolution. */
/* Scale the clock so longer tickless periods can be achieved. The SysTick
is not used as even when its frequency is divided by 8 the maximum tickless
period with a system clock of 16MHz is only 8.3 seconds. Using a prescaled
clock on the 16-bit TIM2 allows a tickless period of nearly 66 seconds,
albeit at low resolution. */
TIM_TimeBaseStructure.TIM_Prescaler = ( uint16_t ) ( SystemCoreClock / lpCLOCK_INPUT_FREQUENCY );
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
TIM_TimeBaseStructure.TIM_Period = ( uint16_t ) ( lpCLOCK_INPUT_FREQUENCY / configTICK_RATE_HZ );
TIM_TimeBaseStructure.TIM_ClockDivision = 0;
TIM_TimeBaseInit( TIM2, &TIM_TimeBaseStructure );
/* Enable the TIM2 interrupt - used for the tick interrupt when the tickless
period is finite. */
/* Enable the TIM2 interrupt. This must execute at the lowest interrupt
priority. */
NVIC_InitStructure.NVIC_IRQChannel = TIM2_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = configLIBRARY_LOWEST_INTERRUPT_PRIORITY; /* Must be set to lowest priority. */
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
@ -216,17 +210,11 @@ const portTickType xRegulatorOffIdleTime = 30;
/* Calculate the reload value required to wait xExpectedIdleTime tick
periods. */
ulCounterValue = ulReloadValueForOneTick * xExpectedIdleTime;
if( ulCounterValue > ulStoppedTimerCompensation )
{
/* Compensate for the fact that TIM2 is going to be stopped
momentarily. */
ulCounterValue -= ulStoppedTimerCompensation;
}
/* Stop TIM2 momentarily. The time TIM2 is stopped for is accounted for as
best it can be, but using the tickless mode will inevitably result in some
tiny drift of the time maintained by the kernel with respect to calendar
time. */
/* Stop TIM2 momentarily. The time TIM2 is stopped for is not accounted for
in this implementation (as it is in the generic implementation) because the
clock is so slow it is unlikely to be stopped for a complete count period
anyway. */
TIM_Cmd( TIM2, DISABLE );
/* Enter a critical section but don't use the taskENTER_CRITICAL() method as
@ -255,13 +243,25 @@ const portTickType xRegulatorOffIdleTime = 30;
}
else if( eSleepAction == eNoTasksWaitingTimeout )
{
/* A user definable macro that allows application code to be inserted
here. Such application code can be used to minimise power consumption
further by turning off IO, peripheral clocks, the Flash, etc. */
configPRE_STOP_PROCESSING();
/* There are no running state tasks and no tasks that are blocked with a
time out. Assuming the application does not care if the tick time slips
with respect to calendar time then enter a deep sleep that can only be
woken by (in this demo case) the user button being pushed on the
STM32L discovery board. */
configPRE_STOP_PROCESSING();
STM32L discovery board. If the application does require the tick time
to keep better track of the calender time then the RTC peripheral can be
used to make rough adjustments. */
PWR_EnterSTOPMode( PWR_Regulator_LowPower, PWR_SLEEPEntry_WFI );
/* A user definable macro that allows application code to be inserted
here. Such application code can be used to reverse any actions taken
by the configPRE_STOP_PROCESSING(). In this demo
configPOST_STOP_PROCESSING() is used to re-initialise the clocks that
were turned off when STOP mode was entered. */
configPOST_STOP_PROCESSING();
/* Restart tick. */
@ -274,36 +274,48 @@ const portTickType xRegulatorOffIdleTime = 30;
}
else
{
/* Trap underflow before the next calculation. */
configASSERT( ulCounterValue >= TIM_GetCounter( TIM2 ) );
/* Adjust the TIM2 value to take into account that the current time
slice is already partially complete. */
configASSERT( ulCounterValue >= TIM_GetCounter( TIM2 ) );
ulCounterValue -= ( uint32_t ) TIM_GetCounter( TIM2 );
/* Trap overflow/underflow before the calculated value is written to
TIM2. */
configASSERT( ulCounterValue < ( uint32_t ) USHRT_MAX );
configASSERT( ulCounterValue != 0 );
/* Update to use the calculated overflow value. */
TIM_SetAutoreload( TIM2, ( uint16_t ) ulCounterValue );
TIM_SetCounter( TIM2, 0 );
/* Restart the TIM2. */
TIM_Cmd( TIM2, ENABLE );
/* Allow the application to define some pre-sleep processing. */
/* Allow the application to define some pre-sleep processing. This is
the standard configPRE_SLEEP_PROCESSING() macro as described on the
FreeRTOS.org website. */
xModifiableIdleTime = xExpectedIdleTime;
configPRE_SLEEP_PROCESSING( xModifiableIdleTime );
/* xExpectedIdleTime being set to 0 by configPRE_SLEEP_PROCESSING()
means the application defined code has already executed the WAIT
means the application defined code has already executed the wait/sleep
instruction. */
if( xModifiableIdleTime > 0 )
{
/* The sleep mode used is dependent on the expected idle time
as the deeper the sleep the longer the wake up time. */
as the deeper the sleep the longer the wake up time. See the
comments at the top of main_low_power.c. Note xRegulatorOffIdleTime
is set purely for convenience of demonstration and is not intended
to be an optimised value. */
if( xModifiableIdleTime > xRegulatorOffIdleTime )
{
/* A slightly lower power sleep mode with a longer wake up
time. */
PWR_EnterSleepMode( PWR_Regulator_LowPower, PWR_SLEEPEntry_WFI );
}
else if( pdTRUE )
else
{
/* A slightly higher power sleep mode with a faster wake up
time. */
@ -311,13 +323,14 @@ const portTickType xRegulatorOffIdleTime = 30;
}
}
/* Allow the application to define some post sleep processing. */
/* Allow the application to define some post sleep processing. This is
the standard configPOST_SLEEP_PROCESSING() macro, as described on the
FreeRTOS.org website. */
configPOST_SLEEP_PROCESSING( xModifiableIdleTime );
/* Stop TIM2. Again, the time the SysTick is stopped for is accounted
for as best it can be, but using the tickless mode will inevitably
result in some tiny drift of the time maintained by the kernel with
respect to calendar time. */
/* Stop TIM2. Again, the time the clock is stopped for in not accounted
for here (as it would normally be) because the clock is so slow it is
unlikely it will be stopped for a complete count period anyway. */
TIM_Cmd( TIM2, DISABLE );
/* Re-enable interrupts - see comments above the cpsid instruction()
@ -328,14 +341,20 @@ const portTickType xRegulatorOffIdleTime = 30;
if( ulTickFlag != pdFALSE )
{
/* Trap overflows before the next calculation. */
configASSERT( ulReloadValueForOneTick >= ( uint32_t ) TIM_GetCounter( TIM2 ) );
/* The tick interrupt has already executed, although because this
function is called with the scheduler suspended the actual tick
processing will not occur until after this function has exited.
Reset the reload value with whatever remains of this tick period. */
configASSERT( ulReloadValueForOneTick >= ( uint32_t ) TIM_GetCounter( TIM2 ) );
ulCounterValue = ulReloadValueForOneTick - ( uint32_t ) TIM_GetCounter( TIM2 );
/* Trap under/overflows before the calculated value is used. */
configASSERT( ulCounterValue <= ( uint32_t ) USHRT_MAX );
configASSERT( ulCounterValue != 0 );
/* Use the calculated reload value. */
TIM_SetAutoreload( TIM2, ( uint16_t ) ulCounterValue );
TIM_SetCounter( TIM2, 0 );
@ -353,9 +372,11 @@ const portTickType xRegulatorOffIdleTime = 30;
sleeping? */
ulCompleteTickPeriods = ( ( uint32_t ) TIM_GetCounter( TIM2 ) ) / ulReloadValueForOneTick;
/* Check for over/under flows before the following calculation. */
configASSERT( ( ( uint32_t ) TIM_GetCounter( TIM2 ) ) >= ( ulCompleteTickPeriods * ulReloadValueForOneTick ) );
/* The reload value is set to whatever fraction of a single tick
period remains. */
configASSERT( ( ( uint32_t ) TIM_GetCounter( TIM2 ) ) >= ( ulCompleteTickPeriods * ulReloadValueForOneTick ) );
ulCounterValue = ( ( uint32_t ) TIM_GetCounter( TIM2 ) ) - ( ulCompleteTickPeriods * ulReloadValueForOneTick );
configASSERT( ulCounterValue <= ( uint32_t ) USHRT_MAX );
if( ulCounterValue == 0 )
@ -379,7 +400,5 @@ const portTickType xRegulatorOffIdleTime = 30;
}
}
#endif /* configCREATE_LOW_POWER_DEMO == 1 */

View File

@ -78,7 +78,8 @@
* See http://www.freertos.org/a00110.html.
*----------------------------------------------------------*/
/* Ensure stdint is only used by the compiler, and not the assembler. */
/* Ensure stdint and C code is only used by the compiler, and not the
assembler. */
#ifdef __ICCARM__
#include <stdint.h>
extern uint32_t SystemCoreClock;
@ -88,30 +89,42 @@
/* Set configCREATE_LOW_POWER_DEMO to one to run the simple blinky low power
demo, or 0 to run the more comprehensive test and demo application. */
#define configCREATE_LOW_POWER_DEMO 1
#define configCREATE_LOW_POWER_DEMO 0
/* A few settings are dependent on the configCREATE_LOW_POWER_DEMO setting. */
#if configCREATE_LOW_POWER_DEMO == 1
#define configCPU_CLOCK_HZ SystemCoreClock
#define configUSE_TICKLESS_IDLE 1
#define configTICK_RATE_HZ ( 100 )
#define configEXPECTED_IDLE_TIME_BEFORE_SLEEP ( 20 + 1 ) /* ( ( 200 / portTICK_RATE_MS ) + 1 ) written out pre-processed to enable #error statements to check its value. */
#define configUSE_TIMERS 0
#else
#define configCPU_CLOCK_HZ SystemCoreClock
#define configSYSTICK_CLOCK_HZ ( SystemCoreClock >> 3UL )
#define configUSE_TICKLESS_IDLE 0
#define configSYSTICK_CLOCK_HZ ( SystemCoreClock >> 3UL ) /* Systick clock is one eighth the system clock. */
#define configTICK_RATE_HZ ( ( portTickType ) 1000 )
#define configUSE_TIMERS 1
#endif /* configCREATE_LOW_POWER_DEMO */
/* Demo specific macros that allow the application writer to insert code to be
executed immediately before the MCU's STOP low power mode is entered and exited
respectively. These macros are in addition to the standard
configPRE_SLEEP_PROCESSING() and configPOST_SLEEP_PROCESSING() macros, which are
called pre and post the low power SLEEP mode being entered and exited. These
macros can be used to turn turn off and on IO, clocks, the Flash etc. to obtain
the lowest power possible while the tick is off. See the comments at the top of
main_low_power.c and in STM32L_low_power_tick_management.c. */
#define configPRE_STOP_PROCESSING()
#define configPOST_STOP_PROCESSING() vMainPostStopProcessing()
/* The configUSE_TICKLESS_IDLE setting is dependent on the users setting of
configCREATE_LOW_POWER_DEMO at the top of this file. */
#define configUSE_TICKLESS_IDLE configCREATE_LOW_POWER_DEMO
#define configCPU_CLOCK_HZ SystemCoreClock
#define configUSE_PREEMPTION 1
#define configUSE_PORT_OPTIMISED_TASK_SELECTION 1
#define configUSE_IDLE_HOOK 1
#define configUSE_TICK_HOOK 1
#define configMAX_PRIORITIES ( 5 )
#define configMINIMAL_STACK_SIZE ( ( unsigned short ) 70 )
#define configTOTAL_HEAP_SIZE ( ( size_t ) ( 10 * 1024 ) )
#define configTOTAL_HEAP_SIZE ( ( size_t ) ( 14 * 1024 ) )
#define configMAX_TASK_NAME_LEN ( 16 )
#define configUSE_TRACE_FACILITY 1
#define configUSE_16_BIT_TICKS 0
@ -119,9 +132,15 @@ demo, or 0 to run the more comprehensive test and demo application. */
#define configUSE_MUTEXES 1
#define configQUEUE_REGISTRY_SIZE 5
#define configCHECK_FOR_STACK_OVERFLOW 2
#define configUSE_RECURSIVE_MUTEXES 0
#define configUSE_RECURSIVE_MUTEXES 1
#define configUSE_MALLOC_FAILED_HOOK 1
#define configUSE_APPLICATION_TASK_TAG 0
#define configUSE_COUNTING_SEMAPHORES 1
/* Software timer related definitions. */
#define configTIMER_TASK_PRIORITY ( configMAX_PRIORITIES - 1 )
#define configTIMER_QUEUE_LENGTH 10
#define configTIMER_TASK_STACK_DEPTH configMINIMAL_STACK_SIZE
/* Co-routine definitions. */
#define configUSE_CO_ROUTINES 0

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,263 @@
/*
FreeRTOS V7.6.0 - Copyright (C) 2013 Real Time Engineers Ltd.
All rights reserved
VISIT http://www.FreeRTOS.org TO ENSURE YOU ARE USING THE LATEST VERSION.
***************************************************************************
* *
* FreeRTOS provides completely free yet professionally developed, *
* robust, strictly quality controlled, supported, and cross *
* platform software that has become a de facto standard. *
* *
* Help yourself get started quickly and support the FreeRTOS *
* project by purchasing a FreeRTOS tutorial book, reference *
* manual, or both from: http://www.FreeRTOS.org/Documentation *
* *
* Thank you! *
* *
***************************************************************************
This file is part of the FreeRTOS distribution.
FreeRTOS is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License (version 2) as published by the
Free Software Foundation >>!AND MODIFIED BY!<< the FreeRTOS exception.
>>! NOTE: The modification to the GPL is included to allow you to distribute
>>! a combined work that includes FreeRTOS without being obliged to provide
>>! the source code for proprietary components outside of the FreeRTOS
>>! kernel.
FreeRTOS is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
FOR A PARTICULAR PURPOSE. Full license text is available from the following
link: http://www.freertos.org/a00114.html
1 tab == 4 spaces!
***************************************************************************
* *
* Having a problem? Start by reading the FAQ "My application does *
* not run, what could be wrong?" *
* *
* http://www.FreeRTOS.org/FAQHelp.html *
* *
***************************************************************************
http://www.FreeRTOS.org - Documentation, books, training, latest versions,
license and Real Time Engineers Ltd. contact details.
http://www.FreeRTOS.org/plus - A selection of FreeRTOS ecosystem products,
including FreeRTOS+Trace - an indispensable productivity tool, a DOS
compatible FAT file system, and our tiny thread aware UDP/IP stack.
http://www.OpenRTOS.com - Real Time Engineers ltd license FreeRTOS to High
Integrity Systems to sell under the OpenRTOS brand. Low cost OpenRTOS
licenses offer ticketed support, indemnification and middleware.
http://www.SafeRTOS.com - High Integrity Systems also provide a safety
engineered and independently SIL3 certified version for use in safety and
mission critical applications that require provable dependability.
1 tab == 4 spaces!
*/
/******************************************************************************
* NOTE 1: This project provides two demo applications. A low power tickless
* project, and a more comprehensive test and demo application. The
* configCREATE_LOW_POWER_DEMO setting in FreeRTOSConfig.h is used to
* select between the two. See the notes on using
* configCREATE_LOW_POWER_DEMO in FreeRTOSConfig.h. This file implements
* the comprehensive test and demo version.
*
* NOTE 2: This file only contains the source code that is specific to the
* full demo. Generic functions, such FreeRTOS hook functions, and functions
* required to configure the hardware, are defined in main.c.
******************************************************************************
*
* main_full() creates all the demo application tasks and a software timer, then
* starts the scheduler. The web documentation provides more details of the
* standard demo application tasks, which provide no particular functionality,
* but do provide a good example of how to use the FreeRTOS API.
*
* In addition to the standard demo tasks, the following tasks and tests are
* defined and/or created within this file:
*
* "Check" timer - The check software timer period is initially set to three
* seconds. The callback function associated with the check software timer
* checks that all the standard demo tasks are not only still executing, but
* are executing without reporting any errors. If the check software timer
* discovers that a task has either stalled, or reported an error, then it
* changes its own execution period from the initial three seconds, to just
* 200ms. The check software timer callback function also toggles an LED each
* time it is called. This provides a visual indication of the system status:
* If the LED toggles every three seconds, then no issues have been discovered.
* If the LED toggles every 200ms, then an issue has been discovered with at
* least one task.
*
* See the documentation page for this demo on the FreeRTOS.org web site for
* full information, including hardware setup requirements.
*/
/* Standard includes. */
#include <stdio.h>
/* Kernel includes. */
#include "FreeRTOS.h"
#include "task.h"
#include "timers.h"
#include "semphr.h"
/* Standard demo application includes. */
#include "PollQ.h"
#include "semtest.h"
#include "dynamic.h"
#include "BlockQ.h"
#include "blocktim.h"
#include "countsem.h"
#include "GenQTest.h"
#include "recmutex.h"
/* ST library functions. */
#include "stm32l1xx.h"
#include "discover_board.h"
#include "discover_functions.h"
#include "stm32l_discovery_lcd.h"
/* Priorities for the demo application tasks. */
#define mainQUEUE_POLL_PRIORITY ( tskIDLE_PRIORITY + 2UL )
#define mainSEM_TEST_PRIORITY ( tskIDLE_PRIORITY + 1UL )
#define mainBLOCK_Q_PRIORITY ( tskIDLE_PRIORITY + 2UL )
/* A block time of zero simply means "don't block". */
#define mainDONT_BLOCK ( 0UL )
/* The period after which the check timer will expire providing no errors
have been reported by any of the standard demo tasks. ms are converted to the
equivalent in ticks using the portTICK_RATE_MS constant. */
#define mainCHECK_TIMER_PERIOD_MS ( 3000UL / portTICK_RATE_MS )
/* The period at which the check timer will expire, in ms, if an error has been
reported in one of the standard demo tasks. ms are converted to the equivalent
in ticks using the portTICK_RATE_MS constant. */
#define mainERROR_CHECK_TIMER_PERIOD_MS ( 200UL / portTICK_RATE_MS )
/*-----------------------------------------------------------*/
/*
* The check timer callback function, as described at the top of this file.
*/
static void prvCheckTimerCallback( xTimerHandle xTimer );
/*-----------------------------------------------------------*/
void main_full( void )
{
xTimerHandle xCheckTimer = NULL;
/* Start all the other standard demo/test tasks. They have not particular
functionality, but do demonstrate how to use the FreeRTOS API and test the
kernel port. */
vStartDynamicPriorityTasks();
vStartBlockingQueueTasks( mainBLOCK_Q_PRIORITY );
vCreateBlockTimeTasks();
vStartCountingSemaphoreTasks();
vStartGenericQueueTasks( tskIDLE_PRIORITY );
vStartRecursiveMutexTasks();
vStartPolledQueueTasks( mainQUEUE_POLL_PRIORITY );
vStartSemaphoreTasks( mainSEM_TEST_PRIORITY );
/* Create the software timer that performs the 'check' functionality,
as described at the top of this file. */
xCheckTimer = xTimerCreate( ( const signed char * ) "CheckTimer",/* A text name, purely to help debugging. */
( mainCHECK_TIMER_PERIOD_MS ), /* The timer period, in this case 3000ms (3s). */
pdTRUE, /* This is an auto-reload timer, so xAutoReload is set to pdTRUE. */
( void * ) 0, /* The ID is not used, so can be set to anything. */
prvCheckTimerCallback /* The callback function that inspects the status of all the other tasks. */
);
if( xCheckTimer != NULL )
{
xTimerStart( xCheckTimer, mainDONT_BLOCK );
}
/* Start the scheduler. */
vTaskStartScheduler();
/* If all is well, the scheduler will now be running, and the following line
will never be reached. If the following line does execute, then there was
insufficient FreeRTOS heap memory available for the idle and/or timer tasks
to be created. See the memory management section on the FreeRTOS web site
for more details. */
for( ;; );
}
/*-----------------------------------------------------------*/
static void prvCheckTimerCallback( xTimerHandle xTimer )
{
static long lChangedTimerPeriodAlready = pdFALSE;
unsigned long ulErrorFound = pdFALSE;
/* Check all the demo tasks to ensure they are all still running, and that
none have detected an error. */
if( xAreDynamicPriorityTasksStillRunning() != pdTRUE )
{
ulErrorFound = pdTRUE;
}
if( xAreBlockingQueuesStillRunning() != pdTRUE )
{
ulErrorFound = pdTRUE;
}
if ( xAreBlockTimeTestTasksStillRunning() != pdTRUE )
{
ulErrorFound = pdTRUE;
}
if ( xAreGenericQueueTasksStillRunning() != pdTRUE )
{
ulErrorFound = pdTRUE;
}
if ( xAreRecursiveMutexTasksStillRunning() != pdTRUE )
{
ulErrorFound = pdTRUE;
}
if( xArePollingQueuesStillRunning() != pdTRUE )
{
ulErrorFound = pdTRUE;
}
if( xAreSemaphoreTasksStillRunning() != pdTRUE )
{
ulErrorFound = pdTRUE;
}
/* Toggle the check LED to give an indication of the system status. If
the LED toggles every mainCHECK_TIMER_PERIOD_MS milliseconds then
everything is ok. A faster toggle indicates an error. */
GPIO_TOGGLE( LD_GPIO_PORT, LD_GREEN_GPIO_PIN );
/* Have any errors been latch in ulErrorFound? If so, shorten the
period of the check timer to mainERROR_CHECK_TIMER_PERIOD_MS milliseconds.
This will result in an increase in the rate at which mainCHECK_LED
toggles. */
if( ulErrorFound != pdFALSE )
{
if( lChangedTimerPeriodAlready == pdFALSE )
{
lChangedTimerPeriodAlready = pdTRUE;
/* This call to xTimerChangePeriod() uses a zero block time.
Functions called from inside of a timer callback function must
*never* attempt to block. */
xTimerChangePeriod( xTimer, ( mainERROR_CHECK_TIMER_PERIOD_MS ), mainDONT_BLOCK );
}
}
}
/*-----------------------------------------------------------*/

View File

@ -0,0 +1,337 @@
/*
FreeRTOS V7.6.0 - Copyright (C) 2013 Real Time Engineers Ltd.
All rights reserved
VISIT http://www.FreeRTOS.org TO ENSURE YOU ARE USING THE LATEST VERSION.
***************************************************************************
* *
* FreeRTOS provides completely free yet professionally developed, *
* robust, strictly quality controlled, supported, and cross *
* platform software that has become a de facto standard. *
* *
* Help yourself get started quickly and support the FreeRTOS *
* project by purchasing a FreeRTOS tutorial book, reference *
* manual, or both from: http://www.FreeRTOS.org/Documentation *
* *
* Thank you! *
* *
***************************************************************************
This file is part of the FreeRTOS distribution.
FreeRTOS is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License (version 2) as published by the
Free Software Foundation >>!AND MODIFIED BY!<< the FreeRTOS exception.
>>! NOTE: The modification to the GPL is included to allow you to distribute
>>! a combined work that includes FreeRTOS without being obliged to provide
>>! the source code for proprietary components outside of the FreeRTOS
>>! kernel.
FreeRTOS is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
FOR A PARTICULAR PURPOSE. Full license text is available from the following
link: http://www.freertos.org/a00114.html
1 tab == 4 spaces!
***************************************************************************
* *
* Having a problem? Start by reading the FAQ "My application does *
* not run, what could be wrong?" *
* *
* http://www.FreeRTOS.org/FAQHelp.html *
* *
***************************************************************************
http://www.FreeRTOS.org - Documentation, books, training, latest versions,
license and Real Time Engineers Ltd. contact details.
http://www.FreeRTOS.org/plus - A selection of FreeRTOS ecosystem products,
including FreeRTOS+Trace - an indispensable productivity tool, a DOS
compatible FAT file system, and our tiny thread aware UDP/IP stack.
http://www.OpenRTOS.com - Real Time Engineers ltd license FreeRTOS to High
Integrity Systems to sell under the OpenRTOS brand. Low cost OpenRTOS
licenses offer ticketed support, indemnification and middleware.
http://www.SafeRTOS.com - High Integrity Systems also provide a safety
engineered and independently SIL3 certified version for use in safety and
mission critical applications that require provable dependability.
1 tab == 4 spaces!
*/
/* ****************************************************************************
* When configCREATE_LOW_POWER_DEMO is set to 1 in FreeRTOSConfig.h main() will
* call main_low_power(), which is defined in this file. main_low_power()
* demonstrates FreeRTOS tick suppression being used to allow the MCU to be
* placed into the Sleep, Low Power Sleep and Stop low power modes. When
* configCREATE_LOW_POWER_DEMO is set to 0 main will instead call main_full(),
* which is a more comprehensive RTOS demonstration.
* ****************************************************************************
*
* This application demonstrates the FreeRTOS tickless idle mode (tick
* suppression) being used to allow the STM32L to enter various low power modes
* during extended idle periods. See
* http://www.freertos.org/low-power-tickless-rtos.html for information on
* tickless operation.
*
* Deeper low power modes have longer wake up periods that lighter low power
* modes, and power is also used simply entering and especially exiting the low
* power modes. How the low power modes are used therefore requires careful
* consideration to ensure power consumption is truly minimised and that the
* embedded device meets its real time requirements. This demo is configured to
* select between four different modes depending on the anticipated idle period.
* Note the time thresholds used to decide which low power mode to enter are
* purely for convenience of demonstration and are not intended to represent
* optimal values for any particular application.
*
* The STM32L specific part of the tickless operation is implemented in
* STM32L_low_power_tick_management.c.
*
* The demo is configured to execute on the STM32L Discovery board.
*
* Functionality:
*
* + Two tasks are created, an Rx task and a Tx task. A queue is created to
* pass a message from the Tx task to the Rx task.
*
* + The Rx task blocks on a queue to wait for data, blipping an LED each time
* data is received (turning it on and then off again) before returning to
* block on the queue once more.
*
* + The Tx task repeatedly blocks on an attempt to obtain a semaphore, and
* unblocks if either the semaphore is received or its block time expires.
* After leaving the blocked state the Tx task uses the queue to send a
* value to the Rx task, which in turn causes the Rx task to exit the
* Blocked state and blip the LED. The rate at which the LED is seen to blip
* is therefore dependent on the block time.
*
* + The Tx task's block time is changed by the interrupt service routine that
* executes when the USER button is pressed. The low power mode entered
* depends on the block time (as described in the Observed Behaviour section
* below). Four block times are used: short, medium, long and infinite.
*
* Observed behaviour:
*
* 1) The block time used by the Tx task is initialised to its 'short' value,
* so when the Tx task blocks on the semaphore it times-out quickly, resulting
* in the LED toggling rapidly. The timeout period is less than the value of
* configEXPECTED_IDLE_TIME_BEFORE_SLEEP (set in FreeRTOSConfig.h), so the
* initial state does not suppress the tick interrupt or enter a low power mode.
*
* 2) When the button is pressed the block time used by the Tx task is increased
* to its 'medium' value. The longer block time results in a slowing of the
* rate at which the LED toggles. The time the Tx task spends in the blocked
* state is now greater than configEXPECTED_IDLE_TIME_BEFORE_SLEEP, so the tick
* is suppressed. The MCU is placed into the 'Sleep' low power state while the
* tick is suppressed.
*
* 3) When the button is pressed again the block time used by the Tx task is
* increased to its 'long' value, so the rate at which the LED is observed to
* blip gets even slow. When the 'long' block time is used the MCU is placed
* into its 'Low Power Sleep' low power state.
*
* 4) The next time the button is pressed the block time used by the Tx task is
* set to infinite, so the Tx task does not time out when it attempts to obtain
* the semaphore, and therefore the LED stops blipping completely. Both tasks
* are not blocked indefinitely and the MCU is placed into its 'Stop' low power
* state.
*
* 5) Pressing the button one final time results in the semaphore being 'given'
* to unblock the Tx task, the CPU clocks being returned to their pre-stop
* state, and the block time being reset to its 'short' time. The system is
* then back to its initial condition with the LED blipping rapidly.
*
*/
/* Kernel includes. */
#include "FreeRTOS.h"
#include "task.h"
#include "queue.h"
#include "semphr.h"
/* ST library functions. */
#include "stm32l1xx.h"
#include "discover_board.h"
#include "discover_functions.h"
#include "stm32l_discovery_lcd.h"
/* Priorities at which the Rx and Tx tasks are created. */
#define configQUEUE_RECEIVE_TASK_PRIORITY ( tskIDLE_PRIORITY + 1 )
#define configQUEUE_SEND_TASK_PRIORITY ( tskIDLE_PRIORITY + 2 )
/* The number of items the queue can hold. This is 1 as the Rx task will
remove items as they are added so the Tx task should always find the queue
empty. */
#define mainQUEUE_LENGTH ( 1 )
/* A block time of zero simply means "don't block". */
#define mainDONT_BLOCK ( 0 )
/* The value that is sent from the Tx task to the Rx task on the queue. */
#define mainQUEUED_VALUE ( 100UL )
/* The length of time the LED will remain on for. */
#define mainLED_TOGGLE_DELAY ( 10 / portTICK_RATE_MS )
/*-----------------------------------------------------------*/
/*
* The Rx and Tx tasks as described at the top of this file.
*/
static void prvQueueReceiveTask( void *pvParameters );
static void prvQueueSendTask( void *pvParameters );
/*-----------------------------------------------------------*/
/* The queue used to pass data from the Tx task to the Rx task. */
static xQueueHandle xQueue = NULL;
/*-----------------------------------------------------------*/
/* Holds the block time used by the Tx task. */
portTickType xSendBlockTime = ( 100UL / portTICK_RATE_MS );
/* The lower an upper limits of the block time. An infinite block time is used
if xSendBlockTime is incremented past xMaxBlockTime. */
static const portTickType xMaxBlockTime = ( 500L / portTICK_RATE_MS ), xMinBlockTime = ( 100L / portTICK_RATE_MS );
/* The semaphore on which the Tx task blocks. */
static xSemaphoreHandle xTxSemaphore = NULL;
/*-----------------------------------------------------------*/
/* See the comments at the top of the file. */
void main_low_power( void )
{
/* Create the semaphore as described at the top of this file. */
xTxSemaphore = xSemaphoreCreateBinary();
configASSERT( xTxSemaphore );
/* Create the queue as described at the top of this file. */
xQueue = xQueueCreate( mainQUEUE_LENGTH, sizeof( unsigned long ) );
configASSERT( xQueue );
/* Start the two tasks as described at the top of this file. */
xTaskCreate( prvQueueReceiveTask, ( const signed char * const ) "Rx", configMINIMAL_STACK_SIZE, NULL, configQUEUE_RECEIVE_TASK_PRIORITY, NULL );
xTaskCreate( prvQueueSendTask, ( const signed char * const ) "TX", configMINIMAL_STACK_SIZE, NULL, configQUEUE_SEND_TASK_PRIORITY, NULL );
/* Start the scheduler running running. */
vTaskStartScheduler();
/* If all is well the next line of code will not be reached as the
scheduler will be running. If the next line is reached then it is likely
there was insufficient FreeRTOS heap available for the idle task and/or
timer task to be created. See http://www.freertos.org/a00111.html. */
for( ;; );
}
/*-----------------------------------------------------------*/
static void prvQueueSendTask( void *pvParameters )
{
const unsigned long ulValueToSend = mainQUEUED_VALUE;
/* Remove compiler warning about unused parameter. */
( void ) pvParameters;
for( ;; )
{
/* Enter the Blocked state to wait for the semaphore. The task will
leave the Blocked state if either the semaphore is received or
xSendBlockTime ticks pass without the semaphore being received. */
xSemaphoreTake( xTxSemaphore, xSendBlockTime );
/* Send to the queue - causing the Tx task to flash its LED. */
xQueueSend( xQueue, &ulValueToSend, mainDONT_BLOCK );
}
}
/*-----------------------------------------------------------*/
static void prvQueueReceiveTask( void *pvParameters )
{
unsigned long ulReceivedValue;
/* Remove compiler warning about unused parameter. */
( void ) pvParameters;
for( ;; )
{
/* Wait until something arrives in the queue. */
xQueueReceive( xQueue, &ulReceivedValue, portMAX_DELAY );
/* To get here something must have arrived, but is it the expected
value? If it is, turn the LED on for a short while. */
if( ulReceivedValue == mainQUEUED_VALUE )
{
/* LED on... */
GPIO_HIGH( LD_GPIO_PORT, LD_GREEN_GPIO_PIN );
/* ... short delay ... */
vTaskDelay( mainLED_TOGGLE_DELAY );
/* ... LED off again. */
GPIO_LOW( LD_GPIO_PORT, LD_GREEN_GPIO_PIN );
}
}
}
/*-----------------------------------------------------------*/
/* Handles interrupts generated by pressing the USER button. */
void EXTI0_IRQHandler(void)
{
static const portTickType xIncrement = 200UL / portTICK_RATE_MS;
/* If xSendBlockTime is already portMAX_DELAY then the Tx task was blocked
indefinitely, and this interrupt is bringing the MCU out of STOP low power
mode. */
if( xSendBlockTime == portMAX_DELAY )
{
portBASE_TYPE xHigherPriorityTaskWoken = pdFALSE;
/* Unblock the Tx task. */
xSemaphoreGiveFromISR( xTxSemaphore, &xHigherPriorityTaskWoken );
/* Start over with the 'short' block time as described at the top of
this file. */
xSendBlockTime = xMinBlockTime;
/* Request a yield if calling xSemaphoreGiveFromISR() caused a task to
leave the Blocked state (which it will have done) and the task that left
the Blocked state has a priority higher than the currently running task
(which it will have). */
portYIELD_FROM_ISR( xHigherPriorityTaskWoken );
}
else
{
/* Increase the block time used by the Tx task, as described at the top
of this file. */
xSendBlockTime += xIncrement;
/* If the block time has gone over the configured maximum then set it to
an infinite block time to allow the MCU to go into its STOP low power
mode. */
if( xSendBlockTime > xMaxBlockTime )
{
xSendBlockTime = portMAX_DELAY;
}
}
EXTI_ClearITPendingBit( EXTI_Line0 );
}
/*-----------------------------------------------------------*/
/* The configPOST_STOP_PROCESSING() macro is called when the MCU leaves its
STOP low power mode. The macro is set in FreeRTOSConfig.h to call
vMainPostStopProcessing(). */
void vMainPostStopProcessing( void )
{
extern void SetSysClock( void );
/* The STOP low power mode has been exited. Reconfigure the system clocks
ready for normally running again. */
SetSysClock();
}
/*-----------------------------------------------------------*/

View File

@ -10,7 +10,7 @@ define symbol __ICFEDIT_region_RAM_start__ = 0x20000000;
define symbol __ICFEDIT_region_RAM_end__ = 0x20003FFF;
/*-Sizes-*/
define symbol __ICFEDIT_size_cstack__ = 0x400;
define symbol __ICFEDIT_size_heap__ = 0x200;
define symbol __ICFEDIT_size_heap__ = 0x0;
/**** End of ICF editor section. ###ICF###*/