1
\$\begingroup\$

I have nucleo-401RE (STM32F401) board. I am trying to setup a timer (TIM4) to work above 2MHz (on bare-metal code).

Per the timer settings below I am supposed to get 10.5MHz. On scope, I am getting only 2MHz.

Am I making the correct configuration? Is there away to make it faster (I got same Hz when setting timer perload register to 3)

#include "stm32f4xx.h"
#include "dbg_pin.h"

#define DBG_PIN_HIGH(p,x)   (p->BSRR = (uint16_t)x)
#define DBG_PIN_LOW(p,x)    (p->BSRR = (uint32_t) x << 16)
#define DBG_PIN_TOGL(p,x)   ((p->ODR & x)? DBG_PIN_LOW(p,x) : DBG_PIN_HIGH(p,x))
        
TIM_HandleTypeDef   hTimSlice;

void SystemClock_Config(void)
{
    RCC_OscInitTypeDef RCC_OscInitStruct;
    RCC_ClkInitTypeDef RCC_ClkInitStruct;

    __HAL_RCC_PWR_CLK_ENABLE();
    __HAL_PWR_VOLTAGESCALING_CONFIG(PWR_REGULATOR_VOLTAGE_SCALE2);

    RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE;
    RCC_OscInitStruct.HSEState = RCC_HSE_ON;
    RCC_OscInitStruct.HSIState = RCC_HSI_OFF;
    RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
    RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE;
    RCC_OscInitStruct.PLL.PLLM = 8;
    RCC_OscInitStruct.PLL.PLLN = 336;
    RCC_OscInitStruct.PLL.PLLP = RCC_PLLP_DIV4;
    RCC_OscInitStruct.PLL.PLLQ = 7;
    if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK) {
        return ;
    }

    RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK |RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2;
    RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
    RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
    RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV2;
    RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1;

    if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_1) != HAL_OK) {
        return ;
    }
}

uint8_t timer_init()
{
    __HAL_RCC_TIM4_CLK_ENABLE();

    hTimSlice.Instance              = TIM4;
    hTimSlice.Init.Prescaler        = 0;
    hTimSlice.Init.Period           = 7;
    hTimSlice.Init.ClockDivision    = 0;
    hTimSlice.Init.CounterMode      = TIM_COUNTERMODE_UP;
    hTimSlice.Init.AutoReloadPreload= TIM_AUTORELOAD_PRELOAD_ENABLE;

    if (HAL_TIM_Base_Init(&hTimSlice) != HAL_OK){
        return 1;
    }
    HAL_NVIC_SetPriority(TIM4_IRQn, 3, 0);
    HAL_NVIC_EnableIRQ(TIM4_IRQn);
    return 0;
}

void TIM4_IRQHandler()
{
    if(__HAL_TIM_GET_FLAG(&hTimSlice, TIM_FLAG_UPDATE) != RESET) {
        if(__HAL_TIM_GET_IT_SOURCE(&hTimSlice, TIM_IT_UPDATE) !=RESET) {
            __HAL_TIM_CLEAR_IT(&hTimSlice, TIM_IT_UPDATE);
        }
    }
    DBG_PIN_TOGL(GPIOC, GPIO_PIN_8);
}

int main(void)
{
    HAL_Init();
    SystemClock_Config();

    setupDbgPin();
    timer_init();
    HAL_TIM_Base_Start_IT(&hTimSlice);

    for(;;);
}

Thanks.

\$\endgroup\$
4
  • \$\begingroup\$ what is bare-metal code? \$\endgroup\$
    – jsotola
    Sep 8 '20 at 23:56
  • \$\begingroup\$ Sorry, I meant no RTOS and no other code. (there is HAL) \$\endgroup\$
    – alsaleem
    Sep 9 '20 at 0:02
  • \$\begingroup\$ Do you set GPIOC, pin 8 to high speed in setupDbgPin function? \$\endgroup\$
    – Misaz
    Sep 9 '20 at 6:57
  • \$\begingroup\$ yes. I did setup GPIOC-8 to high speed. \$\endgroup\$
    – alsaleem
    Sep 10 '20 at 3:41
0
\$\begingroup\$

The ISR assembly list (below). Counted instructions execution time based on arm M4 instruction set and found about (37) cycles. Note that it is just toggling a pin.

With 84MHz, (37) instructions * 12ns = 444ns.

And it is true, you can not achieve >2MHz (or worse) timer rate. I think the idea of using timer with higher rate is to use it with other services such as DMA.

70          if(__HAL_TIM_GET_FLAG(&hTimSlice, TIM_FLAG_UPDATE) != RESET) {
      TIM4_IRQHandler:
08000f80:   ldr     r3, [pc, #40]   ; (0x8000fac <TIM4_IRQHandler+44>)
08000f82:   ldr     r3, [r3, #0]
08000f84:   ldr     r2, [r3, #16]
08000f86:   lsls    r0, r2, #31
08000f88:   bpl.n   0x8000f96 <TIM4_IRQHandler+22>
71              if(__HAL_TIM_GET_IT_SOURCE(&hTimSlice, TIM_IT_UPDATE) !=RESET) {
08000f8a:   ldr     r2, [r3, #12]
08000f8c:   lsls    r1, r2, #31
72                  __HAL_TIM_CLEAR_IT(&hTimSlice, TIM_IT_UPDATE);
08000f8e:   itt     mi
08000f90:   mvnmi.w r2, #1
08000f94:   strmi   r2, [r3, #16]
75          DBG_TOGL(GPIO_PIN_8);
08000f96:   ldr     r3, [pc, #24]   ; (0x8000fb0 <TIM4_IRQHandler+48>)
08000f98:   ldr     r2, [r3, #20]
08000f9a:   lsls    r2, r2, #23
08000f9c:   ite     mi
08000f9e:   movmi.w r2, #16777216   ; 0x1000000
08000fa2:   movpl.w r2, #256        ; 0x100
08000fa6:   str     r2, [r3, #24]
76        }
08000fa8:   bx      lr
08000faa:   nop     
08000fac:   lsls    r4, r3, #17
08000fae:   movs    r0, #0
08000fb0:   lsrs    r0, r0, #32
08000fb2:   ands    r2, r0
\$\endgroup\$
2
  • \$\begingroup\$ Only because you do thing inefficiently. If you really wanted a fast output, you'd drive it from the timer hardware not an ISR. And there are more efficient ways to write the ISR to do the minimal things necessary. \$\endgroup\$ Sep 11 '20 at 17:01
  • \$\begingroup\$ yes, i agree. I am just giving an example of doing "something". Now, i learned i can not do many things in timer ISR >2MHz. AND it is not just a setting problem. \$\endgroup\$
    – alsaleem
    Sep 11 '20 at 17:11

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.