How to set up the Portenta with 480MHz Clock (at least more than 4MHz)

Hi everyone,

i would like to use the 480MHz (at least more than 4MHz) System Clock of the STM32H747XI that is the core of the Portenta H7. In normal (Arduino) Setup it just uses the 4MHz Clock. So i used CubeMX to generate a Setup Code.
In there i select the HSI as the PLL Source in the PLL Source MUX (64MHz) divided by 4 (because it wants to have max 16MHz at this point) multiplied by 60 => 960MHz at this point. And than devided by 2 (because 2 is the least division in DIVP1) => 480MHz.
At next i select the PLLCLK (configured beforehand) and CubeMX shows me the the SysCoreCLK is now 480MHz which is the max on the STM32. when i generate the Code it gives me the following void SystemClock_Config(void):

/**
  * @brief System Clock Configuration
  * @retval None
  */
void SystemClock_Config(void)
{
  RCC_OscInitTypeDef RCC_OscInitStruct = {0};
  RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};

  /** Supply configuration update enable
  */
  HAL_PWREx_ConfigSupply(PWR_DIRECT_SMPS_SUPPLY);
  /** Configure the main internal regulator output voltage
  */
  __HAL_PWR_VOLTAGESCALING_CONFIG(PWR_REGULATOR_VOLTAGE_SCALE0);

  while(!__HAL_PWR_GET_FLAG(PWR_FLAG_VOSRDY)) {}
  /** Macro to configure the PLL clock source
  */
  __HAL_RCC_PLL_PLLSOURCE_CONFIG(RCC_PLLSOURCE_HSI);
  /** Initializes the RCC Oscillators according to the specified parameters
  * in the RCC_OscInitTypeDef structure.
  */
  RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSI;
  RCC_OscInitStruct.HSIState = 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 = 4;
  RCC_OscInitStruct.PLL.PLLN = 60;
  RCC_OscInitStruct.PLL.PLLP = 2;
  RCC_OscInitStruct.PLL.PLLQ = 2;
  RCC_OscInitStruct.PLL.PLLR = 2;
  RCC_OscInitStruct.PLL.PLLRGE = RCC_PLL1VCIRANGE_3;
  RCC_OscInitStruct.PLL.PLLVCOSEL = RCC_PLL1VCOWIDE;
  RCC_OscInitStruct.PLL.PLLFRACN = 0;
  if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
  {
    Error_Handler();
  }
  /** Initializes the CPU, AHB and APB buses clocks
  */
  RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK
                              |RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2
                              |RCC_CLOCKTYPE_D3PCLK1|RCC_CLOCKTYPE_D1PCLK1;
  RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
  RCC_ClkInitStruct.SYSCLKDivider = RCC_SYSCLK_DIV1;
  RCC_ClkInitStruct.AHBCLKDivider = RCC_HCLK_DIV2;
  RCC_ClkInitStruct.APB3CLKDivider = RCC_APB3_DIV2;
  RCC_ClkInitStruct.APB1CLKDivider = RCC_APB1_DIV2;
  RCC_ClkInitStruct.APB2CLKDivider = RCC_APB2_DIV2;
  RCC_ClkInitStruct.APB4CLKDivider = RCC_APB4_DIV2;

  if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_4) != HAL_OK)
  {
    Error_Handler();
  }
}

Then i copy paste it in my Arduino Sketch (and call it of cause in the Setup(void)) but the Portenta H7 runs into a crash after Uploading the sketch (red LED flashing in this specific way)
What am i doing wrong? Is the Portenta H7 capable in running on 480MHz? or do i need something more to configure the Portenta H7 in doing so?

PS: i have some Expierience in including HAL library code in Arduino sketches and so far everything i did worked well (i.e. configure the ADC in high speed interupt continious conversion mode or configure the TIM2 for dynamic frequencies)

1 Like

Just a guess, but normally when you use CubeIDE to generate start-up code, it also include a HAL_Init() function that setup the flash, data, and instruction cache...

hhh

Thx for ur quick response!:slight_smile:
for i.e. ADC configuration via HAL HAL_Init() is not needed but nevertheless i will include it to clear this eventuelly fault!

So I called the HAL_Init() in void setup() before the SystemClock_Config() but there is still the red ERROR LED flashing.

void setup() {

  HAL_Init();
  SystemClock_Config();

  pinMode(LEDR, OUTPUT);
  pinMode(LEDG, OUTPUT);
  pinMode(LEDB, OUTPUT);

  digitalWrite(LEDR, HIGH);
  digitalWrite(LEDG, HIGH);
  digitalWrite(LEDB, HIGH);
}

void loop() {

}

/**
    @brief System Clock Configuration
    @retval None
*/
void SystemClock_Config(void)
{
  RCC_OscInitTypeDef RCC_OscInitStruct = {0};
  RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};

  /** Supply configuration update enable
  */
  HAL_PWREx_ConfigSupply(PWR_DIRECT_SMPS_SUPPLY);
  /** Configure the main internal regulator output voltage
  */
  __HAL_PWR_VOLTAGESCALING_CONFIG(PWR_REGULATOR_VOLTAGE_SCALE0);

  while (!__HAL_PWR_GET_FLAG(PWR_FLAG_VOSRDY)) {}
  /** Macro to configure the PLL clock source
  */
  __HAL_RCC_PLL_PLLSOURCE_CONFIG(RCC_PLLSOURCE_HSI);
  /** Initializes the RCC Oscillators according to the specified parameters
    in the RCC_OscInitTypeDef structure.
  */
  RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSI;
  RCC_OscInitStruct.HSIState = 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 = 4;
  RCC_OscInitStruct.PLL.PLLN = 60;
  RCC_OscInitStruct.PLL.PLLP = 2;
  RCC_OscInitStruct.PLL.PLLQ = 2;
  RCC_OscInitStruct.PLL.PLLR = 2;
  RCC_OscInitStruct.PLL.PLLRGE = RCC_PLL1VCIRANGE_3;
  RCC_OscInitStruct.PLL.PLLVCOSEL = RCC_PLL1VCOWIDE;
  RCC_OscInitStruct.PLL.PLLFRACN = 0;
  if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
  {
    Error_Handler();
  }
  /** Initializes the CPU, AHB and APB buses clocks
  */
  RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK | RCC_CLOCKTYPE_SYSCLK
                                | RCC_CLOCKTYPE_PCLK1 | RCC_CLOCKTYPE_PCLK2
                                | RCC_CLOCKTYPE_D3PCLK1 | RCC_CLOCKTYPE_D1PCLK1;
  RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
  RCC_ClkInitStruct.SYSCLKDivider = RCC_SYSCLK_DIV1;
  RCC_ClkInitStruct.AHBCLKDivider = RCC_HCLK_DIV2;
  RCC_ClkInitStruct.APB3CLKDivider = RCC_APB3_DIV2;
  RCC_ClkInitStruct.APB1CLKDivider = RCC_APB1_DIV2;
  RCC_ClkInitStruct.APB2CLKDivider = RCC_APB2_DIV2;
  RCC_ClkInitStruct.APB4CLKDivider = RCC_APB4_DIV2;

  if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_4) != HAL_OK)
  {
    Error_Handler();
  }
}

/**
    @brief  This function is executed in case of error occurrence.
    @retval None
*/
void Error_Handler(void)
{
  /* USER CODE BEGIN Error_Handler_Debug */
  /* User can add his own implementation to report the HAL error return state */
  __disable_irq();
  while (1)
  {
    digitalWrite(LEDB, LOW);
  }
  /* USER CODE END Error_Handler_Debug */
}

Did u have managed to make the SysCLK of the Portenta H7 faster then 4MHz?

1 Like

I don't have a Portenta but I have an STM32 Discovery Kit with the same STM32H7 MCU. But I don't use Arduino to initialize the board, I use CubeIDE.

It's hard to do this in Arduino IDE since you don't have access to step thru your code like a normal debugger does. Hard to determine where it's failing...

Another way around this is study the RCC section of the STM32 reference manual and configure the clock topology directly using registers

Hi @alexbau
How are you sure that the board is running at only 4 MHz?
From the mbed source code it looks like 400 MHz (25 / 5 * 160 / 2 = 400).

    /* Enable HSE Oscillator and activate PLL with HSE as source */
    RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE | RCC_OSCILLATORTYPE_HSI48;
    if (bypass) {
        RCC_OscInitStruct.HSEState = RCC_HSE_BYPASS;
    } else {
        RCC_OscInitStruct.HSEState = RCC_HSE_ON;
    }
    RCC_OscInitStruct.HSI48State = RCC_HSI48_ON;
    RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
    RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE;
    RCC_OscInitStruct.PLL.PLLM = 5;
    if (lowspeed) {
        RCC_OscInitStruct.PLL.PLLN = 40;
    } else {
        RCC_OscInitStruct.PLL.PLLN = 160;
    }

    RCC_OscInitStruct.PLL.PLLFRACN = 0;
    RCC_OscInitStruct.PLL.PLLP = 2;
    RCC_OscInitStruct.PLL.PLLR = 2;
    RCC_OscInitStruct.PLL.PLLQ = 10;
    RCC_OscInitStruct.PLL.PLLVCOSEL = RCC_PLL1VCOWIDE;
    RCC_OscInitStruct.PLL.PLLRGE = RCC_PLL1VCIRANGE_2;
    if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK) {

Also, I have noticed that the oscillator pin needs to be pulled-up from here:

    /* Enable oscillator pin */
    __HAL_RCC_GPIOH_CLK_ENABLE();
    GPIO_InitTypeDef  gpio_osc_init_structure;
    gpio_osc_init_structure.Pin = GPIO_PIN_1;
    gpio_osc_init_structure.Mode = GPIO_MODE_OUTPUT_PP;
    gpio_osc_init_structure.Pull = GPIO_PULLUP;
    gpio_osc_init_structure.Speed = GPIO_SPEED_FREQ_LOW;
    HAL_GPIO_Init(GPIOH, &gpio_osc_init_structure);
    HAL_Delay(10);
    HAL_GPIO_WritePin(GPIOH, GPIO_PIN_1, 1);

Same issue here on my side. MCU runs just with 400 MHz (even it could be 480 MHz based on spec).

print_log(out, (const char*)"CPU clock    : %ld\r\n", SystemCoreClock);

tells me: MCU runs just with 400 MHz (20% slower as possible)

Why nobody could provide help here?
Why Arduino team has not responded?
Why Arduino team cannot provide really Open Source and all source code needed (not just a Closed Library and staying quiet on reasonable requests)?

Never mind - here is the solution:
This file referenced above as "system_clock_override.c" is NOT part of my installation. It is not in my folders (Arduino15, mbed_portenta 3.0.1).

But, I took this (maybe older version) file and it can set 480 MHz.
It does not help to place into API folder (not compiled automatically), you have to take it to your project.
And it has some functions defined again which conflicts with linking the library (doubled defined). Plus define some macros to make the function available.
I have fixed this file (using #if 0 to get rid of existing functions and define what is needed).
See my version of this file attached (downloaded).

system_clock_override.cpp (11.5 KB)

Use it like this:

void setup() {
    extern uint8_t SetSysClock_PLL_HSE(uint8_t bypass, bool lowspeed);
    SetSysClock_PLL_HSE(1, (bool)false);

It sets now 480 MHz.

Concerns
Touching the clock configuration is very, very sensitive. It does not set just PLL or clock for MCU, it sets also bus and peripheral device clocks.
So, it can happen that MCU has 480 MHz now but other devices, e.g. USB, UART, SPI, SD Card, ETH ... have now a wrong config or a killed config (lost after calling this function).
Or: other functions setting a speed, e.g. UART baud rate, are now off when relying on 400 MHz was core clock (and some PLL divider settings expected).

Luckily, my USB UART is still working as before, with the same speed.
Not sure about SPI and ETH (I need), I have to test if changing core clock affects also other clocks when calling this function.
Use it with care: even core and USB UART seem to be fine - no idea if all other peripherals are still OK.

4 Likes

Which part is closed source? The only thing I've heard of being closed is the original bootloader:

but the open source MCUboot bootloader is now supported:

The important thing to understand is the the Mbed OS core is precompiled in the distributed Arduino boards platforms. This is not done because they want to hide the code from you. It is done to save a ton of time when compiling your sketch. The source code is still available if you want it.

Sure, I know and have realized.
But it is so "painful": you see some H files, definitions, e.g. buffer sizes but changing there does not have any effect.

The compile time is already so long. Compiling once all the code and then modify your project should result in similar compile time.
But the make file in IDE does not seem to be smart: just changing one line in my code (not H file!) - there is almost no difference to clean and compile again.
So, what is the benefit of using precompiled lib when it does not improve compile time?

It hides for sure what the code does (which code is used).
And it does not allow me to debug, to change, to fix.
It is Closed Source for me.

Please,
Arduino team:

  • provide full Open Source code (really all)

  • and an option to build the library myself
    Thank you.

1 Like

I agree. I have enough trouble fumbling my way around in a core even when it is not precompiled!

Even though I do believe that the true spirit of open source is about more than slapping a license on some code and making it available to the public, surely it is going too far to call this "Closed Source".

What is stopping you? Of course you aren't going to get it simply by clicking a button in the IDE, but I don't think it is reasonable to expect that either.

This problem is still present as of May 11 2022 ):

Fortunately, the hack provided by @tjaekel worked for me to get the advertised clock rate. I will post here if I notice any issues.

Wouldn't one of the project managers be willing to set the RCC_OscInitStruct.PLL.PLLN = 192 in the system_clock_override file that @tjaekel linked to, if one of us were to point out the issue on GitHub? I wonder why they set the clock to 400 MHz in the first place. Could it have been an error or do you guys think it was deliberate?

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.