Chaining two 32-bit timers to obtain 64-bit timer resolution

Post your cool example code here.
Post Reply
AndrewBCN
Posts: 105
Joined: Sun Apr 25, 2021 3:50 pm
Answers: 1
Location: Strasbourg, France

Chaining two 32-bit timers to obtain 64-bit timer resolution

Post by AndrewBCN »

Hello,
STM Application Note AN2592 shows how one can chain two 16-bit timers in various STM32 MCUs to obtain a 32-bit timer:
https://www.st.com/resource/en/applicat ... ronics.pdf
Also, dannyf here in this forum has posted code on GitHub for the same purpose: https://github.com/dannyf00/STM32-Chaining-16bit-timers
And Rapita Systems (I have no link to them) has a blog post discussing exactly the same matter: https://www.rapitasystems.com/blog/chai ... er-stm32f4

Below is some code (which I have yet to test) that implements chaining two 32-bit timers to obtain what is effectively a timer with 64-bit resolution. Note that some, but not all STM32 MCUs have two 32-bit general purpose timers which can be chained. In the specific case of the STM32F411CEU6 MCU, these are TIM2 and TIM5.

Code: Select all

/* Chaining two 32-bit timers to obtain 64-bit timer resolution in the STM32F411CEU6

from an example of chaining two 16-bit timers, here:
https://www.rapitasystems.com/blog/chaining-two-16-bit-timers-together-stm32f4

We want TIM2 as the master (counts least significant 32 bits), TIM5 as the slave (counts most significant 32 bits). The result is a 64-bit timer.
*/

// Setup code:

// enable the clocks for the two timer peripherals:
RCC->APB1ENR |= RCC_APB1Periph_TIM2; // both timers are on APB1
RCC->APB1ENR |= RCC_APB1Periph_TIM5;

// Master - TIM2 counts the lower 32 bits 
// TIM2 should be setup to use the clock settings that fit your application
TIM2->PSC = 0x00000000; // no prescaler
/* set clock division to zero: */
TIM2->CR1 &= (uint16_t)(~TIM_CR1_CKD);
TIM2->CR1 |= TIM_CKD_DIV1;
// Set TIM2 in Master Mode
TIM2->CR2 |= 0x20; // MMS (6:4) = 010

/* Slave - TIM5 counts the upper 16 bits */
TIM5->PSC = 0x00000000; // no prescaler
/* set clock division to zero: */
TIM5->CR1 &= (uint16_t)(~TIM_CR1_CKD);
TIM5->CR1 |= TIM_CKD_DIV1;
// Set TIM5 in Slave Mode
TIM5->SMCR |= (TIM_TS_ITR0 | TIM_SlaveMode_External1);

/* enable the two counters: */
TIM5->CR1 |= TIM_CR1_CEN;
TIM2->CR1 |= TIM_CR1_CEN;
One must take some precautions when reading the two 32-bit counter registers to put together a 64-bit counter value. I'll post later the code to do so, when I have tested it thoroughly.
Post Reply

Return to “Code snippets”