2018-11-23: Updated tutorial to cover SDK version 15.2.
2019-02-08: Improved example project (SDK 15.2) and updated instructions accordingly.
Introduction
Scope
The following topics will be included in this tutorial:
- Configuration of the application timer library
- Repeated timers
- Single shot timers
The tutorial will not cover all aspects of the application timer but will focus on the most important uses and API functions.
Necessary prior knowledge
It is expected that you have basic knowledge of how to use Keil or Segger Embedded Studio in order to build and download your application to your kit. Refer to Getting Started in the SDK documentation if this is unfamiliar territory. It is also expected that you are familiar with the concept of interrupts and event handlers. Please refer to the Pin Change Interrupt Example if you need to refresh this topic.
Necessary equipment and software
Hardware:
Software:
- Segger Embedded Studio (SES) or any other supported toolchain, used to build and program the example.
- nRF Connect Programmer or nrfjprog
Other files:
- nRF5 SDK version 15.2.
- Example project: nrf5-application-timer-tutorial. (The completed branch shows the expected result after going through this tutorial).
Within the tutorial project folder there are subfolders for different boards:
pca10040
for the nRF52 DK.pca10040e
for the nRF52 DK emulating nRF52810.pca10056
for the nRF52840 DK.
Preparations
To get started, download and extract the SDK and clone the example project under <SDK>/examples/peripheral/:
The example project configures GPIO inputs and outputs for the buttons and LEDs that will be used in the tutorial. Open the project that suits your target device and prefered toolchain. The application should build without any warnings or errors.
Erase the flash of the DK using nRF Connect Programmer or nrfjprog in order to ensure that no SoftDevice is installed. Program/download the application to the target board. You should be able to control LED 1 with button 1 and 2, and control LED 2 using button 3 and 4.
The Application Timer
The Application Timer library provides a user-friendly way of using the Real Time Counter 1 (RTC1) peripheral to create multiple timer instances. The RTC uses the Low Frequency Clock (LFCLK). Most applications keep the LFCLK active at all times. When using a SoftDevice the LFCLK is always active. Therefore there is normally very little extra power consumption associated with using the application timer. As the clock is 32.768 kHz and the RTC is 24 bit, the time/tick resolution is limited, but it takes a substantial amount of time before the counter wrap around (from 0xFFFFFF to 0). The frequency of the RTC can be lowered by using the 12 bit (1/x) prescaler.
In this part of the tutorial you will configure the library, and use it to create timers that call your timeout event handlers. These can be called repeatedly at a configurable interval or once at a configurable time from now.
Refer to the Application Timer API Reference as needed.
Add required files and includes
The application timer implementation file must be added to the project in order to use the application timer:
<SDK>/components/libraries/timer/app_timer.c
You might also need to add the following files if you are using this as a guide to add the application timer in your own application (unless allready present):
<SDK>/integration/nrfx/legacy/nrf_drv_clock.c
<SDK>/components/libraries/util/app_util_platform.c
Add the following directory to the include paths (the path is relative to project file):
../../../../../../components/libraries/timer
You might also need to add the following includes if you are using this as a guide to add the application timer in your own application (unless already present):
../../../../../../integration/nrfx/legacy
../../../../../../modules/nrfx/drivers/include
Then include the required header files by adding the following lines below the existing include statements:
Make sure that your projects sdk_config.h includes the configuration block for the application timer: This configuration is the default configuration in SDK 15.2, which is recommended in this tutorial. Refer to Application timer functionality configuration for details.
Similarly, make sure to include the configuration block for the clock driver. This is already there if you are using the example project.
Initialization
As a SoftDevice is not enabled in this tutorial, the LFCLK must be requested explicitly. One way of doing this is by using the Clock driver. Add the following function somewhere before main()
:
Add a line calling lfclk_request()
in the start of the main()
function:
The Application Timer should be initialized with the app_timer_init()
function. This must be called before any other calls to the Application Timer API.
Put this line in main()
in order to initialize the app timer:
Create a repeated timer
An application timer in the repeated mode will restart each time it expires. Every time it expires the timeout handler will be called. This makes it suitable for performing a task at a regular interval, such as toggling a LED, which is what you will do now. In this section, we will modify the application so that button 1 starts toggling of LED 1 using an application timer in repeated mode. Button 2 will stop the toggling by stopping the timer.
Application timers are created using app_timer_create()
. This function takes three parameters:
- p_timer_id: pointer to the ID of the timer, which will be populated during the execution of this call.
- mode: either single shot (
APP_TIMER_MODE_SINGLE_SHOT
) or repeated (APP_TIMER_MODE_REPEATED
). - timeout_handler: pointer to the timeout handler.
First, create a variable that can hold the timer ID to be populated by app_timer_create()
. Add the following line to your code, close to the top of the file:
Then you will have to create the timeout event handler. This will toggle LED 1 every time it is called. Add the following function to your code somewhere before the main()
function:
I suggest you wrap the creation of the timer in a function, in order to keep a minimal main()
function. Then the next timer you create in this tutorial can be created within the same function.
Add the following function to your code:
Add the following to main()
before the main loop in order to call the function you just made:
Now the timer is created, but not started. In fact, we have not specified the time between timeouts yet. The timeout is specified in the number of ticks of the RTC1 including prescaling.
It is normally easier to relate to milliseconds than RTC ticks, and the APP_TIMER_TICKS
macro is useful for converting a value in milliseconds to the corresponding number of ticks.
You will now have to modify the button_event_handler()
that is present in the example project in order to let button 1 start the timer. Remove the following code from button_event_handler()
:
..and replace it with this snippet:
Declare the err_code variable before the switch statement by inserting the following line:
The app_timer_start function starts the specified timer (first parameter), and specifies how many ticks from now it shall time out (second parameter). The third parameter is a general-purpose pointer that is passed to the timeout handler. It is set to NULL
in this case as we do not use it. (It is represented by p_context
in the timeout handler repeated_timer_handler()
in this tutorial).
With this code in place, you should be able to build the application without any errors or warnings. Try to build and download it to the development kit (DK). Then you should be able to start toggling of LED 1 by pressing button 1. However, once the LED is toggling there is no way to stop it (other than resetting the chip).
In order to stop the LED from blinking you have to stop the timer. This is done using the app_timer_stop()
function, which takes the timer ID as the only parameter. Modify the button_event_handler()
so that app_timer_stop()
is called when button 2 is pressed, by replacing the following code in the button_event_handler()
:
...with this:
With the latest addition, build the code and download it to the target. You should now be able to stop the toggling of the LED by pressing button 2. The timer can be re-started any time by pressing button 1.
Create a single shot timer
A application timer in single shot mode will expire only once. However, it can always be restarted. Moreover, the number of ticks before it times out can be set to a different value every time it is called (this is also the case for repeated timers).
In this part of the tutorial we will let button 3 start a single shot timer that lights LED 2 when it times out. The first time button 3 is pressed the timer will have a timeout of 1 second. Then the timeout will be incremented by 1 second every time the timer is started. We will keep the functionality of button 4 that it is used to turn off the LED.
Add a new timer ID below the existing m_repeated_timer_id by adding the following line:
Then create the timeout handler shall light LED 2 every time it is called. Add this snippet to your code:
Then modify the create_timers()
by appending the following lines to the end of the function (note that the mode is APP_TIMER_MODE_SINGLE_SHOT
):
Then update the button_event_handler()
by removing:
...and replacing it with:
Declare the static timeout variable before the switch statement by inserting the following line:
Build the code and download it to the target. If you press button 3 you will see that LED 2 is lit after 1 second. Then press button 4, and the LED turns dark. Now press button 3 again and observe that it takes 2 seconds before the LED is lit.
Further Reading
- See the Scheduler tutorial for how to use the scheduler with the application timer (SDK 11).
- The Timer library section of the SDK documentation.
- See the Application Timer API Reference for a complete overview of the application timer API.
P.S.: Please post any questions you might have on the forum and not as a comment below the tutorial. This makes it easier for other users and Nordic employees to see and search for your questions and you will most likely get a faster response.
Top Comments