ガレスタさんのDIY日記

電子回路、Web、組み込み、自作エフェクターを語るblog

NVIC_SetVectorについて

久々にST限定じゃなくARM全般の話ですね。

NVIC_SetVectorについて

Set Interrupt Vectorともあるように割り込みベクターを再セットするAPIです。

主にこうやって使います。

NVIC_SetVector(SPI3_IRQn, (uint32_t)my_irq_handler);

第一引数は割り込み番号です。 第二引数は変更先関数です。

STの例題で話すとSPI3_IRQHandlerというものが初期で定義されています。
これはSPIの何かに反応して割り込みが発生してこのハンドラが呼ばれるものですがそこを無効にしてmy_irq_handlerという自前定義の関数に変更することができます。

ここで以前書いたこの記事とを組み合わせると後述するようなことができます。

gsmcustomeffects.hatenablog.com

例題

まず変更先の関数を定義します。

void my_irq_handler(){
	a++;

}

次にNVIC_APIを使って割り込み類を再定義していきます。

	NVIC_DisableIRQ(SPI3_IRQn);//割り込み無効
	NVIC_SetPriority(SPI3_IRQn, 1);//優先度の指定
	NVIC_SetVector(SPI3_IRQn, (uint32_t)my_irq_handler);//ベクターセット
	NVIC_EnableIRQ(SPI3_IRQn);//割り込み有効

ここまで来るとあとはソフト遷移で割り込みを呼ぶだけです。

NVIC->STIR= SPI3_IRQn;がそれにあたります。

するとこのように周期的に自分の指定した関数をコールできます。

f:id:gsmcustomeffects:20170827070452p:plain

使いどころは悩みますがある割り込みからこの記述を行えばほかの記述に飛べますし処理時間計測とかの応用に使えるのではないでしょうか?
まああくまでこういうこともできるよということなので基本的に非推奨です。
また、元の割り込みは使用しないであろうペリフェラルにしないと動作保証が出来なくなるのでそこらへんもよく考えてやる必要があると思います。

問題点

これをやるにあたりMbedのCMSIS関数周りにはNVIC_SetVectorが入っているのだがCubeMXの吐きだすCMSISヘッダーにはこの定義が含まれていないので自分で作成する羽目になる。

#define NVIC_USER_IRQ_OFFSET          16
#define NVIC_RAM_VECTOR_ADDRESS   (0x20000000)  // Vectors positioned at start of RAM
#define NVIC_FLASH_VECTOR_ADDRESS (0x08000000)
__STATIC_INLINE void NVIC_SetVector(IRQn_Type IRQn, uint32_t vector) {
    uint32_t *vectors = (uint32_t *)SCB->VTOR;
    uint32_t i;

    // Copy and switch to dynamic vectors if the first time called
    if (SCB->VTOR == NVIC_FLASH_VECTOR_ADDRESS) {
        uint32_t *old_vectors = vectors;
        vectors = (uint32_t*)NVIC_RAM_VECTOR_ADDRESS;
        for (i=0; i<IRQn; i++) {
            vectors[i] = old_vectors[i];
        }
        SCB->VTOR = (uint32_t)NVIC_RAM_VECTOR_ADDRESS;
    }
    vectors[IRQn + NVIC_USER_IRQ_OFFSET] = vector;
}

他のcmsisから参考にこのように書いた。

実際HALのような抽象化レイヤーではユーザーがこういう部分をいじることを想定していないというか逆にやらせてはいけないというポリシーがあるのか使わないのは削除しているみたい
なので初期テーブルをいじるようなときは自己責任で!