cancel
Showing results for 
Search instead for 
Did you mean: 

Bugs encountered in F4 RCC HAL code. Are there any workarounds?

Roger Leigh
Associate

Hi folks,

I've got an F429ZI board which works fine, I've run a few samples and I've had zephyr applications running on it no problem. What I now want to do is set up my own small project using the bare minimum of third-party code to begin. I used CubeMX to configure the board with a minimal set of peripherals, set up the clock tree, and then generated the initial code.

Unfortunately, I immediately ran into problems. The generated code went straight into the error handler trying to set up the clocks. After some debugging and hunting around, I found the HAL RCC code was actually buggy and it simply won't work as is! There's even a bug in the suggested fix! I spent some more time looking over the HAL RCC code, and I've found a few more issues with it on top of that.

The bug above was worked around by partially fixing the comparisons, adding a few locals to debug why the checks were failing and returning HAL_OK to get past this point. PLLP still needs an additional fix. But even if this was correct it would fail anyway:

The clock setup here is only called if `RCC->CFGR` is set up, and this check fails, so it never makes use of my clock configuration and this then results in the checks failing because the clock is still using the power-on defaults in `RCC->PLLCFGR`!

It looks like `RCC->CFGR` *would* have been set up later when `HAL_RCC_ClockConfig()` is called, but that happens after `HAL_RCC_OscConfig` is called.

But as it is, that check of `PLLCFGR` is independent of whether or not it actually used my settings. But it's checking the contents of the register against my settings even if it never actually used them! It appears doomed to failure by design. At least, if it took the codepath which skips using the settings, which is the case in the generated code here where sysclk_source hasn't been set to use the PLL before `HAL_RCC_OscConfig` is called. Or so it seems to me looking at it, but I could be wrong.

I'm afraid I've lost a bit of faith in any of this generated code, because now I'm not sure where I am wrong (since I'm very new to this initial setup part) vs where the HAL is buggy or the generated main.c is buggy. If anyone could provide any suggestions or advice I'd certainly appreciate it. I'd like to have some confidence that the HAL is doing the right thing and that I understand what I'm doing! I spent half a day convinced I was at fault and the debugger was misleading me because there was no way the HAL would be doing the wrong thing... but then after checking I find that it's buggy in multiple ways, and that I'm stymied at step 1!

I've also loaded projects for the L4 onto the F4 and they work fine. The L4 HAL doesn't have these issues. See the equivalent code. Looks much more sensible, and the check there is only used to reconfigure the PLL if the configuration changed. But still looks like you need to set sysclk_source up front, which doesn't appear to be happening for the F4 generated code.

Are there any alternatives to try? Are older versions of the HAL missing this bug. I see a post on this forum for a similar problem back in 2015, and I see the HAL sources on GitHub had the problem upon its initial import in 2019.

Thanks all,

Roger

2 REPLIES 2

> Are there any alternatives to try?

Yes. Write your own.

JW

MKwak.1
Associate

Hi there,

I've got a temporily solution to fix this problem. As is you mentioned, SystemClock_Config() function first call HAL_RCC_OscConfig(), which would fail because check in PLL initialization fails:

__HAL_RCC_GET_SYSCLK_SOURCE() != RCC_CFGR_SWS_PLL

To fix this, just enable HSI as system clock before initialize PLL:

void SystemClock_Config(void)
{
  RCC_OscInitTypeDef RCC_OscInitStruct = {0};
  RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};
 
  /** Configure the main internal regulator output voltage
  */
  __HAL_RCC_PWR_CLK_ENABLE();
  __HAL_PWR_VOLTAGESCALING_CONFIG(PWR_REGULATOR_VOLTAGE_SCALE1);
 
  /** [new] Fix pll error: Use HSI before initialize PLL
  */
    RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_SYSCLK;
    RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_HSI;
    if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_5) != HAL_OK)
    {
        Error_Handler();
    }
 
  /** Initializes the RCC Oscillators according to the specified parameters
  * in the RCC_OscInitTypeDef structure.
  */
  RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE;
  RCC_OscInitStruct.HSEState = RCC_HSE_BYPASS;
  RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
  RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE;
  RCC_OscInitStruct.PLL.PLLM = 4;
  RCC_OscInitStruct.PLL.PLLN = 100;
  RCC_OscInitStruct.PLL.PLLP = RCC_PLLP_DIV2;
  RCC_OscInitStruct.PLL.PLLQ = 4;
  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_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
  RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
  RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV2;
  RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1;
 
  /** [new] Disable HSI after successfully initial
   */
    RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSI;
    RCC_OscInitStruct.HSIState = RCC_HSI_OFF;
    RCC_OscInitStruct.PLL.PLLState = RCC_PLL_NONE;
    if(HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
    {
        Error_Handler();
    }
 
  if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_3) != HAL_OK)
  {
    Error_Handler();
  }
}