cortexm:debug

Cortex-M

デバッグ

デバッグ用のコネクタにはJTAG,SWDのどっちかが主流(Cortex-M)
EWARMとCortex-Mマイコンを使用したソフトウェア構成構築ガイド
配線の量考えるとSWDのほうがいいかな.
Cortex-DebugでSVDファイルを渡すとデバッグの際にレジスタの情報を見ることができる。

マイコンがハードウェア的に正常動作が続行不可能に陥った際の例外処理
ARM Cortex-M4コアの例外ハンドラ

  • 用法フォールト
  • バスフォールト
  • メモリ管理フォールト
  • ハードフォールト

これらのフォールトが生じたとき,それぞれに対応した例外処理が動作吸うので,各種割り込みハンドラの中で対応した処理を実施する.
どのフォールトが発生したかは,FSR(Fault Status Register)に反映されるのでこれを読み出す.
Cortex-M4では,HSFRCFSRレジスタがFSRとして用意されている.

  • HSFR(HardFault Status Register) : ハードフォールトの状態が反映されるレジスタ
  • CFSR(Configurable Fault Status Register) : 用法フォールト,バスフォールト,メモリ管理フォールトの状態が反映されるレジスタ

CFSRはハートフォード以外の3つのフォールト状態がまとめて記録されているレジスタである.3つのフォールト・レジスタへはバイト単位,ハーフワード単位のアクセスが可能

  • 31~16bit : UFSR用法フォールト・ステータス・レジスタ
  • 15~8bit : BFSRバスフォールト・ステータス・レジスタ
  • 7~0bit : MMFSRメモリ管理フォールト・ステータス・レジスタ

PC : どこを実行していたか
LR : どこにReturnする予定だったか

0除算

SCBでフォルト機能の管理が可能.CCRの4bit(DIV_0_TRP)を1にセットすると0除算をトラップ可能.

SCB->CCR |= 0x10; // enable div-by-0 trap

0除算が生じると,用法フォールトが発生し,CFSRの25bit(DIVBYZERO)フラグが1になる.

アンアラインド・アクセス

Armv7はアンアラインド・アクセスができるけど,CPU効率が悪くなるのでできないならしないプログラムが書ける方がいい
SCBでフォルト機能の管理が可能.CCRの3bit(UNALIGN_TRP)を1にセットするとアンアラインド・アクセスをトラップ可能.

SCB->CCR |= 0x08; // enable unaligned access

4バイトアライメントに整合していないアクセスをすると,用法フォールトが発生し,CFSRの24bit(UNALIGNED)フラグが1になる.
STM32F4シリーズを使ってみる14 - FatFsとSDカード再考その3(SDIOでDMAした時の不具合対策編) -
アラインされていないデータのアクセス
アンアラインド・データ・アクセス、動作モード、特権アクセス

ある例外が,優先度やそれが無効であることを理由によりできないとき,それらの例外は全部ハードフォールトに昇格される.
この昇格によってハードフォールトが発生したとき,HFSRの30bit(FORCED)が1にセットされる

stm32の場合,stm32fyxx_it.cには割込みハンドラ関数がまとまってる。 HardFault_Handler() もここに入ってるので ここで各レジスタをダンプするアセンブリコード書いておく。

void HardFault_Handler(void)
{
    __asm volatile
    (
        " tst lr, #4                                                \n"
        " ite eq                                                    \n"
        " mrseq r0, msp                                             \n"
        " mrsne r0, psp                                             \n"
        " ldr r1, [r0, #24]                                         \n"
        " ldr r2, handler2_address_const                            \n"
        " bx r2                                                     \n"
        " handler2_address_const: .word prvGetRegistersFromStack    \n"
    );
}
 
void prvGetRegistersFromStack( uint32_t *pulFaultStackAddress )
{
/* These are volatile to try and prevent the compiler/linker optimising them
away as the variables never actually get used.  If the debugger won't show the
values of the variables, make them global my moving their declaration outside
of this function. */
volatile uint32_t r0;
volatile uint32_t r1;
volatile uint32_t r2;
volatile uint32_t r3;
volatile uint32_t r12;
volatile uint32_t lr; /* Link register. */
volatile uint32_t pc; /* Program counter. */
volatile uint32_t psr;/* Program status register. */
 
    r0 = pulFaultStackAddress[ 0 ];
    r1 = pulFaultStackAddress[ 1 ];
    r2 = pulFaultStackAddress[ 2 ];
    r3 = pulFaultStackAddress[ 3 ];
 
    r12 = pulFaultStackAddress[ 4 ];
    lr = pulFaultStackAddress[ 5 ];
    pc = pulFaultStackAddress[ 6 ];
    psr = pulFaultStackAddress[ 7 ];
 
    /* When the following line is hit, the variables contain the register values. */
    for( ;; );
}

CrashCatcherが便利なので参照のこと

参考文献

  • cortexm/debug.txt
  • 最終更新: 2023/06/25
  • by yuqlid