以前、NUCLEO-L452REのUARTを使用している際にUART出力がおかしくなるという問題に遭遇したので、その現象と原因、解決策を紹介します。

環境

マイコンボード:NUCLEO-L452RE
STM32CubeMX ver 4.25.0
STM32CubeL4 ver 1.11.0
SW4STM32

現象

UARTを用いてST-Link経由で文字列を出力したところ、異常な文字が出力された。

具体的には
printf("Hello world!\r\n");
としたところ、ターミナルエミュレータでは以下のような異常な文字列が出力された。

原因

調査したところ、STM32CubeMXでNUCLEO-L452RE用のプロジェクトを生成する際、HSI(High Speed Internal clock:高速内部クロック)のキャリブレーション値の初期設定値が誤っていたため、システム全体のクロックに大きな誤差が生じたためであることが判明しました。

システム内のクロックを外部に出力できるMCO(Master Clock Output)ピンからHSIクロックを出力してみました。 STM32CubeMXの設定は以下の通りです。

このときのクロック波形をオシロで見てみます。

16MHzのクロックを出力しているはずなのに、どうやら13.74MHzしか出ていないようです。
(オシロ自体のサンプリング周波数が100Mspsと低いためクロック波形はなまって表示されています)

さて、 HSIのキャリブレーション値のデフォルトはRCC_HSICALIBRATION_DEFAULTであり、これはstm32l4xx_hal_rcc.h内で以下のように定義されています。
注視すべきは、同じSTM32L4シリーズであっても異なる値となっている点です。

ここで、STM32CubeMXのRCCの設定を確認すると、HSI Calibration Valueには16が設定されています。 STM32L452の初期値は上のstm32l4xx_hal_rcc.hを見ると0x40Uとなっていますので、誤った値が設定されていることになります。

解決方法

STM32CubeMXのRCC設定のHSI Calibration Valueに正しい値を設定することで解決します。 直接 64 (=0x40)という値を入れてもいいですが、汎用性を考えてRCC_HSICALIBRATION_DEFAULTを入力した方がよいでしょう。
ここで、入力欄のデフォルトの10進数書式モードですと、以下の図に示すように64は範囲外の値になってしまい、また文字列は入力できないので"No check"というモードに変更してからRCC_HSICALIBRATION_DEFAULTを入力します。

 

先ほどと同様にMCO出力をオシロで確認しました。

クロック周波数は15.99MHzとなり、問題なく16MHzのクロックが出ています。
このあとprintf出力も直っているか確認したところ、問題なく文字列が表示されました。

今回のトラブルを踏まえて得られたノウハウとしては、 キャリブレーション値に直接値が書き込まれている現状のSTM32CubeMXのRCC設定は汎用性に欠けるため、STM32L452以外のマイコンであってもHSI Calibration ValueにはRCC_HSICALIBRATION_DEFAULTを入力しておいた方がいいでしょう。