2018年10月7日日曜日

Nucleo DCO Thread対応

ダンボール箱に入れてテスト中

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程度
OLED非表示 32fps程度
でした。ADC読み取りのThreadはメイン・ループより優先度が高く、OLED表示中でもADCの読み取りは高速に行われPOTを回すと出音はなめらかに変化します。代わりにプッシュスイッチやロータリーエンコーダーのレスポンスは悪くなってしまいました。

HardFaultが起こる原因はどうやら、u8g2-mbedライブラリをThreadで使ったときに起こるようです。元のu8g2ライブラリは規模が大きくチョイチョイとはいじれなく、mbedに対応させた部分(u8g2_mbed.cpp)もちょっとどうかなという感じなので原因追求はやめておきます。

通信速度や表示も遅いし、SPI版のSSD1306では動作不良だったAdafluit版をmbedに移植されたもの(参考「Nucleo DCO 表示器を考える(メモ)」)もいずれ試してみるつもりです。

他にやったこと


ADC読み取り抑止用フラグを以下のように宣言していましたが、
// Suppress ADC
bool isSuppressAdc = false;
ADC読み取りをThread化した場合に反映されなくなったので
// Suppress ADC
volatile bool isSuppressAdc = false;
とvolatile指定すると正常動作しました。「isSuppressAdc」は外部割り込み(InterruptIn)で値を変更しているので、volatile指定しないとThread内で読み取る時には最適化されて無視されてしまうようです。

RotaryEncoderライブラリをcallback()を使うように変更しました。

電源電圧を15Vまで測定できるように抵抗の分圧値を変更しました。精度は悪くなりますが使える電源電圧を融通するため。

0 件のコメント:

コメントを投稿