2015-11-01

Everything related to digital electronics is related to time. Timer, counter, frequency, pulse width, clock and time are the most common words one may find in this arena. Microcontrollers just like humans need heart-beats and these come from clock sources. Apart from system clock, timers are clock sources that can be used as heart-beats for various applications. All modern micros are embedded with timer-counter modules and generally they are used for generating time bases, counting pulses, measuring time periods of waveforms, generating pulse width modulation (PWM) signals, triggering external devices and timing special events. STM32 micros have several timers designed for such applications. However unlike most 8-bit micros which possess two/three timers with limited functionalities, the timers of STM32s are very elaborate and complex. This explains why documentations related to timer modules take about 25% of any STM32 reference manual.

Before we begin exploring STM32 timers, I must point out that I won’t be able to cover every aspect of all timer modules as they are vast and need lot of explanations, something which is beyond the scope of a single post. This is why in this issue we shall explore the very basics of timer modules enough to get STM32 timers to work.

Classification of STM32 Timers

The timers in a STM32 micro can be classified as follows:

Advanced Timers

General Purpose Timers

Basic Timers

Of these three types of timers the first two are common to all. The third is available only in larger variants. The number of timers of a given class also varies with the capacity or the size of the STM32 micro. For instance, STM32F103C8T6 has one advance timer while STM32F103VET6 has two advanced timers. STM32CubeMX can be used to determine which timers are available in a given STM32 micro unless you wish to get lost in piles of documentations.



In my own words, I will describe STM32 timer as follows.

General purpose (GP) timers have all the features of a typical timer-counter module. They are pretty much the same as the ones we have seen in most 8-bit micros. They can be used for any timer-counter-related purpose and so they are named as such. PWM generation, input capture, time-base generation and output compare are the basic uses of a GP timer. Typically in a STM32 micro you’ll find more GP timers than other classes of timers. Studying GP timers clears the basic concepts.

Basic timers are timers that don’t have I/O channels for input capture/PWM generation and so they are strictly used for time-base generation purposes. Basic timers are available only in large capacity STM32 micros and are the simplest of all timers.

Advanced timers are almost the same as GP timers but they additionally have the ability to generate complementary PWM signals as well as generate brake and dead-time for such signals. These features make them suitable for applications related to motor control, inverters, SMPSs and other power electronics-related tasks. In most STM32 micros, there is at least one such timer. In larger STM32s, there can be two.

Every timer in a STM32 micro is independent of the others and so they don’t share any common resource. The only things that are common are the register types, naming convention and their operating principles. With only a few exceptions, timer modules are more-or-less compatible amongst STM32 micro families. You’ll not find significant differences when you migrate from STM32F1xx series to STM32F4xx series. This is not true for other internal hardware like GPIO ports, ADCs, etc.



Timer Overview

Typically most STM32 timers consist of a 16-bit auto reload counter and a 16-bit prescaler. The prescaler is responsible for dividing the incoming clock signal from a clock source as per our need. The auto-reload counter is loaded just we used to load timer registers of 8-bit MCUs. The only thing exceptional about it is its auto reloading feature. In old school 8-bit MCUs, we needed to reload the timer after every interrupt or after every overflow. This is not required in STM32s as it is automatically handled.

Unlike most other MCUs in which timers usually count incrementally, STM32 timers can count up, down or center-aligned. However in most applications up counting is more preferable over other methods.

With the exception of basic timers, all STM32 timers have four independent I/O channels (TIMx_CH1 – TIMx_CH4). These can be used as follows:

Input Capture

Output Compare or PWM

One Pulse Mode

Timers can be clocked by:

Internal Clock

External Clock Sources

External Mode 1 (TI1 and TI2 pins)

External Mode 2 (ETR pin)

Internal Trigger (ITRx)

Interrupt and DMA events occur when the followings occur:

Update

Counter overflow/underflow

Counter initialized

Others

Trigger

Counter Start

Counter Stop

Counter Initialize

Others

Input Capture / Output Compare

Others

The table below summarizes some common features of STM32 timers.

From all of these info we can draw the versatility of STM32 timers although they are not very easy to deal with in the beginning. This is why unlike my previous tutorials on other STM32 peripherals, we will study the timers concurrently with their applications and coding.

Timer Registers

Before we start coding, I must point out that perhaps the most complex sets of registers in a STM32 micro belong to timer-counter modules. We don’t need all of them for a specific application and so to avoid complexity we will only discuss about those registers that we will be needing for a particular task. A few registers will always be needed but other will needed for specific tasks like input capture/ output compare. Another important thing to note on these registers is the fact that though all registers in an ARM micro are 32-bit wide, for timer modules and most hardware peripherals most of the bits are reserved. This makes handling them easy. To yet simplify handling these during coding I have used my own built definitions and functions similar to ST’s SPL. MikroC libraries also take care some of such. Just for reference check out the register map of any timer module. I have shown one below.

Design Considerations

A few things should be remembered before coding and designing hardware. These are as follows:

Timer modules to be used should be enabled first by setting appropriate RCC_APBx_ENR register bits. Individual counters, DMA and interrupts are enabled after setting up everything else.

Right after power on reset every bit of internal registers of a STM32 micro are in their default reset values. For timer registers the default is all zeroes, meaning everything disabled. Thus the ones we don’t need to use, need not to be forcefully cleared. Usually this is the case for most internal hardware peripherals. However if you need to change stuffs on the fly, you better reset all settings just to avoid running down to the jaws of a software bug or unprecedented results.

Timers can’t be used like RTCs for a number of factors and so it is not always wise to use them as precision time keepers. If accuracy is not very important, timers can be used for general time-keeping purposes. No doubt timers are accurate than wasteful delay functions but they are not good as dedicated RTCs.

When using GPIOs for capture/compare mode, make sure which I/O pins are being used because sometimes the I/O pins related to these functionalities can be remapped elsewhere. Use STM32CubeMX to find out which pins can be used with a given timer.

AFIO block must be enabled and used for remapping I/O pins since capture/compare are alternative functions of ordinary GPIOs. AFIO block should be enabled even if remapping is not used. GPIOs should be configured as AFIOs for compare/output modes.

When using input capture mode, be sure of the maximum input voltage level of an incoming waveform. Not all but most I/O pins are 5V tolerant. I will however strongly suggest not to cross the VDD limit, typically 3.3V. Similarly when using compare mode, be sure that the end device like a LED or an opto-coupler connected to a compare pin doesn’t draw too much current. Simply do not exceed the specified GPIO electrical specs. This is very important.

The internal oscillator of STM32 micros are quite accurate (1% tolerant) but if more precision is needed, it is better to use well calibrated external clock generators or precise external crystals.

Be aware of clock system prescalers, multipliers and clock sources.

Remember APB2 bus peripherals can run at maximum system clock speed while APB1 bus peripherals are limited to half of that speed. Thus APB1 timers may not run at the same clock speed as the APB2 timers.

Since internal clock speed of each timer is dependent on its APB bus speed, it is a must know to which APB bus a given timer belongs. On MikroE’s Timer Calculator utility software this is actually the MCU clock speed. Use STM32CubeMX and MikroC compiler’s project editor to determine APB bus speeds. I have shown an example below. Here APB1 timers are being fed with 36MHz while APB2 timers are being fed by 72MHz.

Hardware and Software

As with the previous issues, MikroC for ARM C compiler is what we will be using. Except the code examples which are dependent on MikroC compiler’s library functions, most of the codes can be ported to other compilers. We’ll also get introduced with a new software tool and obviously STM32CubeMx and ST-Link software will play their parts. I’ll also use my developed SPL libraries.

The hardware that I’ll introduce here is a STM32F103VET6 ARM Cortex M3 development board. I chose this micro as it has all types of timer I discussed, eight timers – two advance timers, two basic timers and four GP timers. In terms of all hardware resources, it is a beast that comes in a LQFP100 SMD package with 512kB of flash, 64kB of RAM and 82 I/Os. The board on which it is embedded is also neatly designed with proper readable labels – simply a nice STM32 development board.

Time Base Generation

This is most basic use of a timer. In this mode of operation, we will have to program the timer as such that it’ll periodically generate timed events. For this purpose we can use any timer but I recommend using either GP timers or basic timer (if any). There is no specific reason for this recommendation. It is just my way of using STM32 timers – use things that have been designed for their purposes.

For making time base generators we need to follow a few steps and the overall thing is very easy. We will use interrupt-based method. First we need to determine which timer we will be using and what should be the frequency of the timer interrupt. We, then, need to calculate the values for the prescaler (PSC), the auto-reload register (ARR) and the repetition counter (RCR) (if any). Repetition counters are available only in advanced timers only. We can use the following formula for determining interrupt rate:

RCR will be zero unless used or available and so generally the formula will be:

TIMx clock is dependent on APB bus clock.

Finally we will be enabling timer interrupts and the counter module itself.

Sometime along its path in the world of embedded systems, MikroElektronika (MikroE), a well-reputed microcontroller-based hardware and software solution provider, developed a free tool called Timer Calculator. This tool made life easy. We can use it to generate codes necessary for timer interrupts. It generate codes for MikroC, MikroBasic or MikroPascal. Originally Timer Calculator used support PIC and AVR platforms only but recently after unveiling MikroE ARM compilers, ARM platforms were incorporated with it. If we have fairly some sound idea of how things are working inside a STM32, we can avoid all the time-consuming, tiring silly calculations and use it to complete your job easily. We just need to select the STM32 family, MCU clock and desired interrupt rate either in terms of time or in terms of frequency. There are also some preset code examples than can also be used to get a head start.

Timer Calculator can be downloaded from here:

http://www.libstock.com/projects/view/398/timer-calculator.

In terms of registers we just need to deal with the following registers only when we need to generate time-bases. I will not explain them in details as their coding will do that.

Code Examples

MikroE Timer Calculator Example

There’s nothing to say about this example as the software says for itself. We just need to the stuffs as marked in the image below. In this example two LEDs connected to GPIOC pin 6 and 7 will toggle logic states every 500ms. Pin C7 LED flashes due to timer 6 update interrupt and pin C6 LED blinks due one main loop execution. After every interrupt, interrupt flags in the timer status registers need to be cleared.

The following setup is used for this code example and the next.

Demo video link: https://www.youtube.com/watch?v=L3TVU7BGK9s.

There are some ignorable limitations of the MikroE Timer Calculator software. For instance it doesn’t support advance timers but I don’t find it as a problem. You can use any other timer like Timer 4 for instance, generated codes for it and then renumber/rename the registers. Another reason for which I’m not bothered by this is due to the fact that advance timers are meant for dedicated advanced tasks and not for silly time-keeping.

Multiple Timer Interrupt Example

This example is just like the previous one except this time the code is written with my SPL functions and two timers are running simultaneously with different clock frequencies. LEDs connected to GPIOC 6 and 7 pins flash to show the update rates of these timers. An advance and a GP timer are used in the demo.

Demo video link: https://www.youtube.com/watch?v=jyPUu5JqZyU.

External Clock Drive/Counter Example

In the beginning I stated that timers can be driven with external clock sources. STM32 timers can be driven with three types of external sources. We can use this facility to count pulses coming from a sensor like a Hall position sensor. We can also cascade several such timers to form a high precision timer. In this example, we will see how this is done.

The following hardware setup is used.

Please refer to the code. Note GPIOA 0 pin is used as the input of the external clock source. Here I connected a button to stimulate the external clock source. Note that the AFIO block has been enabled but no pin remapping is used. I avoided pin remapping to keep things simple although pin remapping is not hard. The following code sets up external clock properties.

As you can see the external clock source will only be sensed during rising edge transitions. Its input channel enabled and selected.

The rest of the code in the timer setup simply state how much to count before invoking an interrupt and should there be any prescaling for the incoming signal. This code makes my STM32 board sense two rising edges before invoking an interrupt and toggling a LED connected to GPIOC 6 pin. Pretty simple.

Demo video link: https://www.youtube.com/watch?v=jCVWCoJeqec.

Pulse Width Modulation (PWM)

Pulse Width Modulation (PWM) is another feature that is common in most modern MCUs. With PWM outputs, we can generate waveforms as per our need and so often it is said that PWMs mimic analogue outputs. In reality PWMs don’t output continuous analogue voltages like Digital-Analogue Converters but rather output variable width pulses that have average values. A low-pass RC filter can be used to obtain continuous output voltages while blocking high frequency PWM waveform components.

All STM32s have timer-counter modules. Except basic timers, all STM32 timers are capable of generating PWM outputs. Each timer has four such outputs called PWM channels. Advance timers have up to seven PWM channels each – six for complementary PWM and a single channel. Now you can see that even a small STM32 micro has many PWM channels unlike most other MCUs. What’s more interesting is the fact that these PWM channels are not fixed to some dedicated GPIO port pins, some can be remapped elsewhere.

In any work, there are two ways – the easy way and the hard way. Both ways have their cons and pros. Yeah I’m taking about MikroC’s PWM library. MikroE packed their compilers with libraries literally for everything inside a micro and PWM library is just another example. These libraries are easy to use. With minimum knowledge one can work wonders with such libraries. Prototyping an idea from abstracts then becomes a matter of a few lines of code. However as a developer MikroE can’t provide solution for all possible permutations and combinations. Sometimes even from the point of view of a programmer that’s unnecessary and so they only provide the basic libraries that are mostly used. In such cases it the responsibility of a coder to code stuffs as required. Too much library dependence is also not good for smart coding.

We already dealt with four registers for generating time bases. Apart from those we need a few more registers for PWM generation. Actually three sets of registers are needed to be dealt with. For advance timers, we will need to handle one more register for dead time and other purposes apart from the other three.

Firstly I will introduce the timer capture/compare mode register set. This set comprises of two separate registers TIMx_CCMR1 and TIMx_CCMR2. TIMx_CCMR1 controls capture/compare channel 1 and 2 while channel 3 and 4 are controlled by TIMx_CCMR2.

Please note that unlike other registers the CCMR registers have dual role and so the register maps have two separations. The top rows of these registers are for output/compare mode while the bottom layers are for input capture mode. CCxS bits of these registers determine the corresponding capture/compare channel’s I/O direction. For PWM mode these bits will be zero. The next stuff that we need to set in these registers are OCxM bits. These bits should be set either as 110 or 111 for PWM mode. The difference in these two bit settings is the PWM output type – i.e. normal PWM or inverted PWM.

The next set of registers we will be dealing with are the TIMx_CCER registers. For all timers their bit orientations are same but advance timers have additional bits for additional functionalities. The purposes of these registers are simply enabling the desired capture/compare channels and setting their polarities.

For every timer except the basic ones, there are four capture/compare registers TIMx_CCRx which correspond to four capture/compare channels. Changing the values in them during compare mode allows us to change PWM width or duty cycle. The value that will be set in the TIMx_ARR register will correspond to maximum PWM count or 100% duty cycle. PWM generation is accomplished by comparing the values in TIMx_CCRx registers and TIMx_CNT register. Note that complementary channels have no such registers and that’s because they output complementary signals of their respective ordinary channels.

The registers I mentioned so far are common to all timers with capture/compare functionalities. Using them will allow us to accomplish common PWM-related tasks. However there is one more register that we will be needing to handle for more advanced tasks and so it is available only in advanced timers. This register is called Timer Brake and Dead Time Register, TIMx_BDTR. It is important to note that when using advanced timers for PWM generation the MOE bit should be set or else there will be no PWM output.

Since PWM generation and input capture are alternative functions of a GPIO pin, we need to enable and use AFIO registers as well for alternative functions of those pins. Provided it is supported, with AFIO registers we can remap/reposition default PWM/input capture pins to some other pins. AFIO_MAPR and AFIO_MAPR2 registers are used for such purposes.

Code Examples

MikroC PWM Library Example

All MikroC compilers come with PWM libraries. MikroC for ARM has PWM libraries for different variants of ARM chips – Stellaris M3s, M4s and STM32s. We are only concerned with STM32 variants. Only four functions are what are needed to be understood for using this library and these are as follows:

PWM_TIMn_Init – initializes timer module in PWM mode by setting desired PWM frequency.

PWM_TIMn_Set_Duty – sets PWM duty, PWM type and channel.

PWM_TIMn_Start – starts respective timer module in PWM mode.

PWM_TIMn_Stop – stops respective timer module.

As you can see these built-in library functions are very easy to get started with. However be sure of pin remapping. Random pin remapping may lead to undesired problems. Remember pins are mapped in groups. This is the common mistake most people make with PWM library.

The code example for this demo is a glowing-fading running light. General purpose timers 3 and 4 are used to generate 6 kHz PWMs in eight channels. At any instance two adjacent LEDs will glow and fade opposite to each other. The brightness of one will gradually increase with the gradual decrement of the pervious LED’s brightness.

Note that in the code I didn’t set the AFIO registers and I also didn’t enable the timer APB buses. This is the advantage of using MikroC libraries. The PWM library took care of these.

The following hardware setup is used for this demo:

Demo video link: https://www.youtube.com/watch?v=uxBXF32cAgQ.

There are few limitations of the PWM library. One is the inability to support complementary PWMs and its related stuffs in advance timers. Secondly unlike most other MCUs, maximum PWM duty cycle needs to be read in the software as there’s no fixed timer count value that corresponds to this. Thus you will need to know this value either with a USART or a LCD even if you are not planning to use one in your project. Now this is where we pay the price of getting things easily. Basically it is not MikroE’s fault. STM32 timers are made in such a way and we’ll see why in the next example codes.

Output Compare Mode (PWM) Example

Sometimes a programmer needs to get out of the luxury of prebuilt compiler libraries and apply his/her skills. I pointed out some limitations of MikroC compiler’s PWM library and so we need to go around to avoid these limitations. By this way we will have a good understanding of the output compare mode (A.K.A PWM mode) and also optimize coding as per need.

Firstly check out the code. You’ll notice that GPIO pins are setup as AFIO push-pull output pins and that’s because PWM mode is the alternative functionality of an I/O pin. Note that unlike timer 8 in which it is not possible, timer 1 channels can be remapped. However I didn’t apply remapping for the sake of simplicity.

In this example, both advance timers of STM32F103VET6 micro are used. The PWM outputs have a common frequency and it is 45 kHz. The PWM frequency can be calculated just like what we saw in time-base generation examples.

The maximum duty cycle count will be equal to the value that will be set in the timer auto-reload register, TIMx_ARR. In my example, I set PSC zero and ARR 1599 and so now you can see why the PWM frequency is 45 kHz. TIM1_ARR and TIM8_ARR registers are set 1599. Thus 100% duty cycle equals 1599 count, 50% duty cycle equals 800 counts and so forth. As said before, PWM is achieved by comparing counts in the TIMx_CCRn and TIMx_CNT registers. All channels of a timer will have the same PWM frequency but their duty cycles may be different.

The following lines of code set these parameters.

Then the following code states PWM parameters. PWM mode simply states whether or not to generate inverted PWM. The code also states which PWM channel to use and what should be its polarity. Finally it enables some controls to enable PWM generation.

For PWM modes interrupts are not necessary as PWM generation is an independent process. To control PWM duty cycle, we only need to load values to TIMx_CCRn, anything between 0 to TIMx_ARR value.

The following hardware setup is used:

The code simply brightens and dims eight LEDs connected to timer PWM channels.

TIM1_CCR4 =

Show more