Are you interested in making your own timer? In this post, you can learn about the EFM32 timer module including clock sources, interrupts, and how to set up the timer.
The EFM32 TIMER module can be used for a number of different functions which include up/down count, input capture or output compare. Figure 1.1 shows a block diagram with the TIMER module overview.
The TIMER can be clocked from several sources, both internal and external. It includes a 16-bit counter with multiple modes, input capture, output compare and PWM. If more bits are needed, the 3 timers can be connected, resulting in a counter with 32 or 48 bits. Also, it can generate Reflex Signals to trigger other peripherals such as the ADC, USART or DAC and interrupts to wake up the processor.
2. Clock Sources
The clock input for the counter can come from 3 different sources: peripheral high frequency clock (HFPERCLK), compare/capture channel 1 input (TIMn_CC1 pin or PRS channel) or underflow/overflow from the lower numbered neighbour timer. If the peripheral high frequency clock is chosen, it can be prescaled up to a factor of 1024.
To select the TIMER clock source, the bitfields CLKSEL and PRESC from TIMERn_CTRL register are used. The first bitfield selects the clock source for the timer and the second sets the prescaler for the HFPERCLK (if selected).If using compare/capture channel 1 for clock input using TIMn_CC1 pin then it should be configured as an input on the GPIO module. AN0012 GPIO contains more details on pin configuration.
3. Interrupts and PRS
The timer has 5 output events that can trigger an interrupt. All except the buffer overflow also trigger a Reflex Signal:
• Counter Underflow
• Counter Overflow
• Compare match, input capture or buffer overflow (one per Compare/Capture channel)
To enable one or more interrupts, TIMERn_IEN register must be written with the corresponding interrupt enable bits. Also, the NVIC vector for the corresponding interrupt line must be enabled. There is also a function available on the emlib to activate timer interrupts: void TIMER_IntEnable(TIMER_TypeDef *timer, uint32_t flags);
The TIMER always generates Reflex outputs (one HFPERCLK cycle pulse), on the above output events regardless of the TIMERn_IEN register or if it is selected by a PRS channel.
If an interrupt is generated the interrupt flag can be read from the TIMERn_IF register and cleared by writing TIMERn_IFC.
4. Counting Modes and Timer Set up
4.1. Timer Setup
Prior to start using the timer some configurations must be performed to ensure that it works as intended. In order to facilitate this configuration there is an emlib function available: void TIMER_Init(TIMER_TypeDef *timer, const TIMER_Init_TypeDef *init);
By using this function the user will be able to configure the following parameters:
• Start counting when configuration is complete
• Counter running during debug
• Prescaler if HFPER clock selected
• Clock selection
• Action on falling edge input
• Action on rising edge input
• Counting mode
• DMA request clear on active
• X2 or X4 quadrature decode mode (if used)
• One shot or continuous counting
• Timer start/stop/reload by other timers
4.2. Up, Down and Up/Down
The counter can be used for up, down or up/down counting with different behaviors in each mode:
• Up-count: counts up until it reaches the value in TIMERn_TOP, then it is reset to 0 before counting up again (if in continuous counting). When the counter goes from TIMERn_TOP to 0 an overflow event occurs.
• Down-count: counts from TIMERn_TOP down to 0, then it is reloaded with the value of TIMERn_TOP. When the counter goes from 0 to TIMERn_TOP an underflow event occurs.
• Up/Down-count: counter starts at 0 and counts up until it reaches TIMERn_TOP. Then it counts down to 0 and starts counting up again. Overflow occurs when the counter goes from TIMERn_TOP to TIMERn_TOP-1 and underflow when it goes from 0 to 1.
The counting mode is configured by using the Counting Mode parameter in the TIMER_Init function. It can also be configured by writing MODE bitfield in the TIMERn_CTRL register:
4.3. Quadrature Decoding
Quadrature Decoding is the 4th counting mode available on the TIMER module. This mode will increment or decrement the counter based on two signals which are 90 degrees out of phase. These signals are tapped from CC0 (Channel A) and CC1 (Channel B).
If Channel A is leading Channel B the counter will be incremented. If the opposite happens, it will be decremented. The Quadrature Decoder can be set to X2 or X4 modes. The difference between these two modes is the number of counter increments/decrements for each signal period. In X2 mode the counter will be incremented/decremented 2 times per signal period, and on X4 mode it will be incremented/ decremented 4 times.
Like the other counting modes, the quadrature mode can be configured using the Counting Mode parameter plus the X2 or X4 quadrature decode mode parameter from the Timer_Init() function. Alternatively the user can write directly to MODE bitfield in the TIMERn_CTRL register.
4.4 Hardware Count Control
The TIMER can be configured to start/stop/reload autonomously when there is a rising and/or falling edge on the input, This is done using the parameters Action on falling edge input and Action on rising edge input from the Timer_Init() function. The options available for each parameter are:
• No action
• Start counter without reload
• Stop counter without reload
• Reload and start counter
4.5 Counter software examples
4.5.1 Up Count
Project timer_up_count demonstrates how to configure the timer for up counting operation together with interrupt handling. The EFM32 wakes up from a TIMER overflow every 2 seconds and toggles LED 0 on the STK, or PC0 (P4.3 on the protoboard) on the DVK.
4.5.2 Quadrature Decoding
For quadrature decoding example there is project timer_quad_decode which can only be used for the EFM32_Gxxx_STK. This demonstration uses PB0 and PB1 from the STK to simulate the 2 signals that will be decoded. To visualize the decoding the buttons should be pressed in two different order resulting in different LED movements.
Executing the following cycle will light up the LEDs from right to left.
• Press and hold PB0
• Press and hold PB1 while holding PB0
• Release PB0
• Release PB1
Executing the following cycle will light up the LEDs from left to right.
• Press and hold PB1
• Press and hold PB0 while holding PB1
• Release PB1
• Release PB0