Using Timers on nRF52
Prerequisites
This is tutorial is not intended to be a guide for learning C language or about the Nordic SDK platform. It’s primary target is to provide developers a concise guide about integrating peripheral modules and features into active applications.
If you are a beginner, I would recommend you look into an nRF52 Project Setup guide like this one.
Another easy way to get started with coding, without bothering with all basic stuff like files and driver inclusion, check out this Code Generation Tool
nrf52 Code Generator: https://vicara.co/nrf52-code-generator
Timer in a Microcontroller?
A Timer can be said to be a specialized clock, which is used to measure intervals on a microcontroller. In a microcontroller, a timer can be used to tune the processing speed of an operation, set delays and also to synchronize user input and communication between a variety of peripheral devices.
As a result, timers form a very integral component of a microcontroller operations and having the skill to control the timer and its operations become an essential skill for any Embedded Systems developer.
Timer on nRF52
There are 5 instances of the timer on the nRF52832 module. Each module can be used independently.
The timer/counter runs on the high-frequency clock source (HFCLK) and includes a four-bit (1/2X) prescaler that can divide the timer input clock from the HFCLK controller. Clock source selection between PCLK16M and PCLK1M is automatic according to TIMER base frequency set by the prescaler. The TIMER base frequency is always given as 16 MHz divided by the prescaler value.
Programming Timer on nRF52832
Include Header
To use timer functions, nrf_drv_timer.h needs to be included into the project. It is available at SDK/integration/nrfx/legacy folder.
Update sdk_config.h
In this file, we need to enable TIMER_ENABLED flag and also the corresponding instance.
Thus, if Timer-3 is to be used, we need to enable TIMER3_ENABLED 1
Add Timer definition to Main File
Define Instance
static const nrf_drv_timer_t m_timer = NRF_DRV_TIMER_INSTANCE(1);
Timer Callback Function
static void timer_handler(nrf_timer_event_t event_type, void* p_context)
{
switch(event_type)
{
case NRF_TIMER_EVENT_COMPARE0:
break;
case NRF_TIMER_EVENT_COMPARE1:
break;
case NRF_TIMER_EVENT_COMPARE2:
break;
case NRF_TIMER_EVENT_COMPARE3:
break;
case NRF_TIMER_EVENT_COMPARE4:
break;
case NRF_TIMER_EVENT_COMPARE5:
break;
default:
break;
}
}
This will be called every time a timer channel is triggered.
Initialize Timer Function
//@brief Function for Timer init function
static void timer_init()
{
//Can use the below values as default
nrf_drv_timer_config_t timer_cfg;
timer_cfg.bit_width = NRF_TIMER_BIT_WIDTH_16; //user defined
timer_cfg.frequency = NRF_TIMER_FREQ_31250Hz; //user defined
timer_cfg.interrupt_priority = APP_IRQ_PRIORITY_LOW; //user defined
timer_cfg.mode = NRF_TIMER_MODE_TIMER;
ret_code_t err_code = nrf_drv_timer_init(&m_timer, &timer_cfg, timer_handler);
APP_ERROR_CHECK(err_code);
//Timers 0,1 and 2 have 4 channels. Timers 3 and 4 have 6 channels.
//The below function needs to be called for each channel.
nrf_drv_timer_extended_compare(&m_timer, NRF_TIMER_CC_CHANNEL0, nrf_drv_timer_ms_to_ticks(&m_timer ,1000), NRF_TIMER_SHORT_COMPARE0_CLEAR_MASK, true);
}
Now all you need to do is call timer_init(); function from within the main function.
nrf_drv_timer_extended_compare
needs to be called once for each timer channel used and it’s 4th parameter decides if the timer channel is a one shot or if it reloads. Interrupt priority options are 2, 3, 6, 7.
Conclusion
With the above steps anyone can easily get started with incorporating timers into their application code.
NOTE
There is another easier method to initialize and auto-generate code for nRF52. This tool, will handle all library additions and code generations for a variety of peripherals like SPI, I2C, UART etc.