How to access low level registers or How to set TIM1 to 128Mhz

Post here first, or if you can't find a relevant section!
adc_problems
Posts: 11
Joined: Sat Sep 24, 2022 4:05 pm

How to access low level registers or How to set TIM1 to 128Mhz

Post by adc_problems »

Hello Girls and Guys!

I am currently in need to generate a high resolution high speed PWM signal.
I wanted to use TIM1 in 128Mhz mode but cant figure out how to set it.

(Using PlatformIO with platform:ststm32 core in Visual Code studion on windows - code runs on a STM32G071GBU6N)


CubeIDE generates the following clock and timer initilizing code:

Code: Select all

static void MX_TIM1_Init(void)
{
  TIM_ClockConfigTypeDef sClockSourceConfig = {0};
  TIM_MasterConfigTypeDef sMasterConfig = {0};
  TIM_OC_InitTypeDef sConfigOC = {0};
  TIM_BreakDeadTimeConfigTypeDef sBreakDeadTimeConfig = {0};
  
  htim1.Instance = TIM1;
  htim1.Init.Prescaler = 0;
  htim1.Init.CounterMode = TIM_COUNTERMODE_UP;
  htim1.Init.Period = 65535;
  htim1.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
  htim1.Init.RepetitionCounter = 0;
  htim1.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE;
  sClockSourceConfig.ClockSource = TIM_CLOCKSOURCE_INTERNAL;
  
and

Code: Select all

void SystemClock_Config(void)
{
  RCC_OscInitTypeDef RCC_OscInitStruct = {0};
  RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};

  HAL_PWREx_ControlVoltageScaling(PWR_REGULATOR_VOLTAGE_SCALE1);

  RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSI;
  RCC_OscInitStruct.HSIState = RCC_HSI_ON;
  RCC_OscInitStruct.HSIDiv = RCC_HSI_DIV1;
  RCC_OscInitStruct.HSICalibrationValue = RCC_HSICALIBRATION_DEFAULT;
  RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
  RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSI;
  RCC_OscInitStruct.PLL.PLLM = RCC_PLLM_DIV1;
  RCC_OscInitStruct.PLL.PLLN = 16;
  RCC_OscInitStruct.PLL.PLLP = RCC_PLLP_DIV2;
  RCC_OscInitStruct.PLL.PLLQ = RCC_PLLQ_DIV2;
  RCC_OscInitStruct.PLL.PLLR = RCC_PLLR_DIV4;
  
  RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK
                              |RCC_CLOCKTYPE_PCLK1;
  RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
  RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
  RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV1;
How would I go and translate that to STM32duino?
ag123
Posts: 1655
Joined: Thu Dec 19, 2019 5:30 am
Answers: 24

Re: How to access low level registers or How to set TIM1 to 128Mhz

Post by ag123 »

128 Mhz is probably above the cpu clock frequency
e.g. for stm32f103c8 72 Mhz, you can probably at best get like 72 Mhz or more commonly half or less like 36 Mhz.

for the 'official' STM core, the wiki is here
https://github.com/stm32duino/Arduino_Core_STM32/wiki

hardware timer API is documented here:
https://github.com/stm32duino/Arduino_C ... er-library

the codes for using a hardware timer is generally like

Code: Select all

HardwareTimer *timer = new HardwareTimer(TIM1);

void mycallback() {
	digitalWrite( LED_BUILTIN, ! digitalRead(LED_BUILTIN));
}

void setup() {

pinMode(LED_BUILTIN, OUTPUT);

timer->pause();
timer->setOverflow(2, HERTZ_FORMAT); // 2 hz
timer->attachInterrupt(mycallback);
timer->refresh();
timer->resume();

}

void loop() {
  // nothing here, the timer does all the work
  // you can place other codes in the main loop
}

adc_problems
Posts: 11
Joined: Sat Sep 24, 2022 4:05 pm

Re: How to access low level registers or How to set TIM1 to 128Mhz

Post by adc_problems »

The STM32G071GBU6N can do 128Mhz on TIM1 and TIM15.
Screenshot 2024-02-15 091626.png
Screenshot 2024-02-15 091626.png (49.55 KiB) Viewed 723 times
As fas as i see it, the Arduino implementation does not support it because it needs changes in the clock path.
Screenshot 2024-02-15 091727.png
Screenshot 2024-02-15 091727.png (49.41 KiB) Viewed 723 times
TIM1 (not interested in TIM15) needs to run on clock source PLLQ not the usual TPCLK which would result in 64Mhz counting speed.

My first post includes the nativ STM32 registers that CubeIDE sets to make that happen.

I did not find a reference on how to set these native hardware registers under arduino / platformIO or with the offical core.
User avatar
fpiSTM
Posts: 1738
Joined: Wed Dec 11, 2019 7:11 pm
Answers: 91
Location: Le Mans
Contact:

Re: How to access low level registers or How to set TIM1 to 128Mhz

Post by fpiSTM »

Simply redefine the system core clock config:
https://github.com/stm32duino/Arduino_C ... ock_config
adc_problems
Posts: 11
Joined: Sat Sep 24, 2022 4:05 pm

Re: How to access low level registers or How to set TIM1 to 128Mhz

Post by adc_problems »

fpiSTM wrote: Thu Feb 15, 2024 8:27 am Simply redefine the system core clock config:
Thank you very much!

Do i need to call

Code: Select all

SystemClock_Config()
or does it get called by the framework/core at startup?
User avatar
fpiSTM
Posts: 1738
Joined: Wed Dec 11, 2019 7:11 pm
Answers: 91
Location: Le Mans
Contact:

Re: How to access low level registers or How to set TIM1 to 128Mhz

Post by fpiSTM »

It will be called automatically as it replace the weak function.
adc_problems
Posts: 11
Joined: Sat Sep 24, 2022 4:05 pm

Re: How to access low level registers or How to set TIM1 to 128Mhz

Post by adc_problems »

Understood, thanks.

For anyone else searching: the

Code: Select all

WEAK void SystemClock_Config(void)
lives in generic_clock.c in your variants folder.

Code compiles without issues but somehow i still only get 3,9Khz clock frequency for 14 bit resolution.
I would have expected (128000000/(2^14)) = 7,8Khz.

Maybe the HardwareTimer lib interferes somehow?

I get exactly the same frequency for both TIM1 and TIM2 with 14bit resolution and the clock config that CubeIDE generates for the 128Mhz clock to TIM1 setting.
I tried replacing the weak function just to make sure my one gets actually loaded. Didnt make a difference.

Not sure why that doesnt work.

I did:

Code: Select all

main.h

Code: Select all

  HardwareTimer *Tim1 = new HardwareTimer(TIM1);
  
  HardwareTimer *Tim2 = new HardwareTimer(TIM2);
  
  Tim1->setMode(1, TIMER_OUTPUT_COMPARE_PWM1, PWM_Green);
  Tim1->setOverflow(16384);
  Tim1->setPrescaleFactor(1);
  Tim1->setCaptureCompare(1, 8000);
  
  Tim2->setMode(2, TIMER_OUTPUT_COMPARE_PWM1, PWM_Blue_2);
  Tim2->setOverflow(16384);
  Tim2->setCaptureCompare(1, 8000);
  
I set the PrescaleFactor just for testing purpose to check if it changes anything.

I also did:

Code: Select all

  uint32_t herz = Tim1->getTimerClkFreq();
  uint32_t herz2 = Tim2->getTimerClkFreq();
 
Both return 64Mhz instead of Tim1 returning 128Mhz.
64Mhz is right because i am seeing 3,9Khz on the Pin however it should be 128Mhz.

So it looks like my clock config does not apply correctly? Is there anything i can test?
adc_problems
Posts: 11
Joined: Sat Sep 24, 2022 4:05 pm

Re: How to access low level registers or How to set TIM1 to 128Mhz

Post by adc_problems »

Found it!

I need to switch the TIM1 clock mux by:

Code: Select all

	PeriphClkInit.PeriphClockSelection = RCC_PERIPHCLK_TIM1;
	PeriphClkInit.Tim1ClockSelection = RCC_TIM1CLKSOURCE_PLL;
I found that snippet while searching around.

Code: Select all

Tim1->getTimerClkFreq();
Still reports 64Mhz but the Oscope shows: 128Mhz clock.

Interestingly CubeIDE does not generate that code. So i assume native Cube users will also see that issue.

Maybe supporting TIM1 high speed mode is something that should be availabe inside the HardwareTimer Lib, afterall, faster PWM never hurts for dimming applications. If you dont need the speed, you will benefit from the increased resolution at the same speed.
dannyf
Posts: 447
Joined: Sat Jul 04, 2020 7:46 pm

Re: How to access low level registers or How to set TIM1 to 128Mhz

Post by dannyf »

if you need 128Mhz PWM, there is something wrong with your solution, or the application of this MCU in your solution. In that case, it is much helpful for you to say "here is a problem I want to solve. what would you suggest as a solution?"

if you indeed need 128Mhz PWM (for whatever reason):
1) use dedicated hardware: fpga, or dedicated pwm generator chips.
2) pick a chip with high clock rate or high resolution timer - some newer STM32 chips have them.
3) lower the pwm's resolution. you can later on increase the resolution through dithering, or composite pwm generators.
...
ag123
Posts: 1655
Joined: Thu Dec 19, 2019 5:30 am
Answers: 24

Re: How to access low level registers or How to set TIM1 to 128Mhz

Post by ag123 »

@dannyf I think the op kind of mentions that stm32g071 timers can do 128 Mhz.
it is something quite interesting to explore, that is practically VHF, FM radio frequencies if you noted.
in a sense if that is possible, even for that matter use it as an oscillator, mix it with FM radio waves from an antenna 88-108 Mhz,
the IF frequencies would be 20 to 40 Mhz, low pass filter that and one can literally recover the FM I'd guess.

A notion of running at such high VHF frequencies, is I'd guess there would be challenges such as that even stray capacitances or line inductances would literally distort the signals and probably look more like sine waves etc. There'd likely be other challenges too (e.g. that a long enough wire can become an antenna and the signals simply radiate out at 128 Mhz)
Post Reply

Return to “General discussion”