ADC読み取りをなめらかにするために(読み取りのサンプリングレートをあげる)、ADC読み取りと、OLED表示をそれぞれ別Threadにしました。
最初は「mbed OS 5のThread」でやったように
0 波形生成 Ticker
1 ADC読み取り Thread(priority:高)
2 メインループ Thread(priority:普通) デジタル入出力
3 OLED表示 Thread(priority:低)
としたのですが、実行時に「HardFault」というメッセージがUARTに出力されて、プログラムが停止しました。そこで、Thread化する対象を切り分けてようすをみました。
「ADC読み取り」、「OLED表示」ともにThread化
Nucleo_DCO_Test20 https://github.com/ryood/Nucleo_DCO/tree/master/mbed/Nucleo_DCO_Test20エラー出力
728 DCO Test20 0 4 288.28 0.000 8007 0.424: 0 4 314.53 0.091 30961 0.101: 0 4 224.00 -0.442 37380 0.576: MasterAmplitude:0.413 DisplayMode:1 21.6 fps 12.08 V SuppressADC:0 729 DCO Test20 0 4 287.10 0.000 7889 0.424: 0 4 313.23 0.091 31095 0.098: 0 4 227.34 -0.423 37212 0.574: MasterAmplitude:0.・ム DisplayMode:1 21.6 fps 12.07 V SuppressA ++ MbedOS Fault Handler ++ FaultType: HardFault Context: R0 : BDD13786 R1 : 00000000 R2 : 00000001 R3 : 20007B78 R4 : 00000000 R5 : 20000460 R6 : 00000002 R7 : 00000000 R8 : 20007C00 R9 : 00000017 R10 : 20000000 R11 : 3FF51367 R12 : FFFFFFFF SP : 20009980 LR : 08011B73 PC : 080122B8 xPSR : 81070000 PSP : 20009918 MSP : 2007FFD8 CPUID: 411FC270 HFSR : 40000000 MMFSR: 00000000 BFSR : 00000000 UFSR : 00000100 DFSR : 0000000B AFSR : 00000000 Mode : Thread Priv : Privileged Stack: PSP -- MbedOS Fault Handler -- ++ MbedOS Error Info ++ Error Status: 0x80FF013D Code: 317 Module: 255 Error Message: Fault exception Location: 0x8003577 Error Value: 0x80122B8 Current Thread: Id: 0x20005EBC Entry: 0x8005B85 StackSize: 0x1000 StackMem: 0x20008C48 SP: 0x2007FF70 -- MbedOS Error Info --
UARTに実行時間(秒)を含めたログを出力していて、Fault時は「729」となっているので12分9秒でFaultです。
「FaultType: HardFault」とあり、「Error Status: 0x80FF013D Code: 317 Module: 255」ともあるので原因は「HardFault」のようです。
参考「Docs › Reference › Platform › Error handling」
HardFaultは「APS」さんの「初心者講座 → Cortex-M編 → 例外のタイプ」によると、
優先順位の関係、または他のハンドラが無効にされていて、実行できないときのデフォルト(すべて)のフォールトとなっています。
STM32F767ZIのReference manual(RM0410)の「10.1.2 Interrupt and exception vectors」の「Table 46. STM32F76xxx and STM32F77xxx vector table」には
All class of faultとあります。「なんかしらんけど例外が起こった。レジスタを見て調べてちょーだい」ということらしいです。
「OLED表示」のみThread化(ADC読み取りはメイン・ループ内で)
Nucleo_DCO_Test21 https://github.com/ryood/Nucleo_DCO/tree/master/mbed/Nucleo_DCO_Test21エラー出力
<...> 2946 DCO Test21 3 4 473.76 0.000 7973 0.425: 4 3 232.66 -0.036 31011 0.464: 1 2 176.05 0.486 31835 0.161: MasterAmplitude:0.505 DisplayMode:1 31.9 fps 12.08 V SuppressADC:0 2946 DCO Test21 3 4 474.95 0.000 7939 0.425: 4 3 ++ MbedOS Fault Handler ++ FaultType: HardFault Context: R0 : 00363234 R1 : 00000000 R2 : FFFFFFFF R3 : 00000005 R4 : 20000460 R5 : 00000001 R6 : 00000005 R7 : 00000000 R8 : 20007B40 R9 : 0000002B R10 : 8F6D0AD0 R11 : 406D29AA R12 : 08004955 SP : 200072A8 LR : 08011B73 PC : 08011B7E xPSR : 81070000 PSP : 20007240 MSP : 2007FFD8 CPUID: 411FC270 HFSR : 40000000 MMFSR: 00000000 BFSR : 00000004 UFSR : 00000000 DFSR : 0000000B AFSR : 00000000 Mode : Thread Priv : Privileged Stack: PSP -- MbedOS Fault Handler -- ++ MbedOS Error Info ++ Error Status: 0x80FF013D Code: 317 Module: 255 Error Message: Fault exception Location: 0x8003577 Error Value: 0x8011B7E Current Thread: Id: 0x2000649C Entry: 0x80035CD StackSize: 0x1000 StackMem: 0x200064E8 SP: 0x2007FF70 -- MbedOS Error Info --
OLEDのみThread化した場合も「HardFault」しました。こちらは「2946秒(約50分)」です。
「ADC読み取り」のみThread化(OLED表示はメイン・ループ内で)
Nucleo_DCO_Test21 https://github.com/ryood/Nucleo_DCO/tree/master/mbed/Nucleo_DCO_Test22
ログ
<...> 90650 DCO Test22 0 3 152.01 0.000 30356 0.201: 0 3 231.93 0.525 20543 0.234: 0 3 276.62 0.819 61141 0.125: MasterAmplitude:0.791 DisplayMode:1 2.0 fps 12.11 V SuppressADC:0 90651 DCO Test22 0 3 151.54 0.000 30485 0.201: 0 3 230.71 0.523 20576 0.227: 0 3 276.08 0.816 61141 0.124: MasterAmplitude:0.790 DisplayMode:1 2.0 fps 12.42 V SuppressADC:0 90651 DCO Test22 0 3 151.67 0.000 30457 0.202: 0 3 232.01 0.525 20543 0.225: 0 3 278.65 0.832 61309 0.124: MasterAmplitude:0.789 DisplayMode:1 2.0 fps 12.12 V SuppressADC:0
「ADC読み取り」のみThread化した場合は、「90651秒(24時間以上)」動作させましたが、Faultは起こりませんでした。
メイン・ループの処理時間は
OLED表示中 2.0fps程度でした。ADC読み取りのThreadはメイン・ループより優先度が高く、OLED表示中でもADCの読み取りは高速に行われPOTを回すと出音はなめらかに変化します。代わりにプッシュスイッチやロータリーエンコーダーのレスポンスは悪くなってしまいました。
OLED非表示 32fps程度
HardFaultが起こる原因はどうやら、u8g2-mbedライブラリをThreadで使ったときに起こるようです。元のu8g2ライブラリは規模が大きくチョイチョイとはいじれなく、mbedに対応させた部分(u8g2_mbed.cpp)もちょっとどうかなという感じなので原因追求はやめておきます。
通信速度や表示も遅いし、SPI版のSSD1306では動作不良だったAdafluit版をmbedに移植されたもの(参考「Nucleo DCO 表示器を考える(メモ)」)もいずれ試してみるつもりです。
他にやったこと
ADC読み取り抑止用フラグを以下のように宣言していましたが、
// Suppress ADCADC読み取りをThread化した場合に反映されなくなったので
bool isSuppressAdc = false;
// Suppress ADCとvolatile指定すると正常動作しました。「isSuppressAdc」は外部割り込み(InterruptIn)で値を変更しているので、volatile指定しないとThread内で読み取る時には最適化されて無視されてしまうようです。
volatile bool isSuppressAdc = false;
RotaryEncoderライブラリをcallback()を使うように変更しました。
電源電圧を15Vまで測定できるように抵抗の分圧値を変更しました。精度は悪くなりますが使える電源電圧を融通するため。
0 件のコメント:
コメントを投稿