NucleoのClock系について

(2014.12.11 作成)

 STM32Nucleo基板のClock系について、電源と同じく少し注意点がありますので、ここで紹介します。

 まず参考までにSTM32F401のクロックツリーを載せます。STM32ではRTC(Real-Time Clock)およびIWDT(Independent watchdog timer)用に供給される低速クロックと、コアやペリフェラルに供給される高速クロックの2種類があります。またさらにそれぞれに外部からクロック入力する場合と内部発信回路によるクロック生成の2種類があり、計4種類のクロック源があります。そしてこれらはそれぞれLSE, LSI, HSE, HSIと呼ばれています。

 当然内部発信クロックは余計な部品が載らないため、小さく・安く出来るというメリットがあるのですが、一方精度は少し劣ります。このため出来れば外部からクロックを入力するLSE, HSEを使用したいところです。

 そこでUser Manualを読んでみるとNucleo基板の外部クロックとして以下の選択肢ができるとされています。

  • HSE (External High Speed clock)
  1. ST-LINKとして使用されているマイコンのMCO出力をクロック源とする
  2. 自分で基板上のX3に振動子を実装する。
  3. CN7のPin29にクロックを外から入れる
  4. 使用しない
  • LSE (External Low Speed clock)
  1. 自分で基板上のX2に振動子を実装する。
  2. CN7のPin25にクロックを外から入れる
  3. 使用しない

 そしてここからがややこしいところなのですが、Nucleo基板には2種類の仕様があり、シールで設定が記載されています。右の写真は管理人の手元にある基板で"MB1136 C-02"と記載されています。

 このシールの内容によってどの外部クロック源を利用するかが異なっており、


Low Speed Clock High Speed Clock
MB1136 C-01 外部クロックを使用しない 外部クロックを使用しない 
MB1136 C-02 X2に振動子を実装済 ST-Linkから供給

となっています。

 C-02の方が高精度であるため、購入したものがこちらであれば特に何をしなくても外部クロック源が利用できます。一方C-01は基板のST-Link部分を切断してもそのまま動くのでそういった意味での使い勝手はよさそうです。

CubeMX利用時の注意

 STマイクロさん謹製のCコード作成補助ツールCubeMXでは上記2種類の仕様どちらでも動作するように初期のクロックが内部クロックになっています。C-02基板をお持ちの方は外部クロックに設定されるのがよいと思います。たとえばNucleo F401の場合は以下の通りとすれば規定の84MHzで動作します。

  • HSE :BYPASS Clock Source
  • PLLM : /8
  • PLLN : x336
  • PLLP : /4
  • PLLQ : /7

またCubeMXを使用しない場合は以下のような初期化コードを使用すれば同じ結果となります。

HAL_RCC_DeInit();   // If this is not implemented, HAL_RCC_OscConfig returns HAL_ERROR

RCC_ClkInitTypeDef RCC_ClkInitStruct;
RCC_OscInitTypeDef RCC_OscInitStruct;

__PWR_CLK_ENABLE();
__HAL_PWR_VOLTAGESCALING_CONFIG(PWR_REGULATOR_VOLTAGE_SCALE2);

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 = 8;
RCC_OscInitStruct.PLL.PLLN = 336;
RCC_OscInitStruct.PLL.PLLP = RCC_PLLP_DIV4;
RCC_OscInitStruct.PLL.PLLQ = 7;
HAL_RCC_OscConfig(&RCC_OscInitStruct);

 ポイントは最初にHAL_RCC_DeInit()を呼ぶことです。これが無いとHAL_RCC_OscConfig()でエラーが発生することがありました。