ARM: Cortex-M3 割込みハンドラと weakシンボルと C++
mbed関連はC++言語採用なんですね。
今までC言語プロジェクトだけだったのでC++で気づいた点を。
コンパイラは「Sourcery g++ Lite for ARM」です。
LPC1768: Cortex-M3はARMv7-Mアーキテクチャ。
*アセンブラで記述されたスタートアップコード
最近はCMSISにおまけで付いていたアセンブラで記述された
「startup_LPC17xx.s」というのを使っている。
割込みハンドラーは「weakシンボル」付きなので
C言語で同じ名前の関数を定義すれば自動でC言語関数が
リンクされるという仕組み。
これ結構便利なんです。
たとえば「SysTick_Handler」はスタートアップコード中で以下のように
「weak宣言」されています。
.weak SysTick_Handler
.type SysTick_Handler, %function
SysTick_Handler:
B .
.size SysTick_Handler, . - SysTick_Handler
C言語からは、
void SysTick_Handler(void)
{
/* some code */
}
とだけ書けば「割込み関数定義」は終了します。
後はリンカが適切にシンボル解決してくれます。
*C++言語で割込みハンドラを記述する
上のC言語割込みハンドラのファイル拡張子を「.cpp」に変えてC++言語で
コンパイルするとコンパイル、リンク共にOKですが、
割込みが全く動きません!
動かないなら警告くらい出してほしいと思います。(爆
正解はこうでした。
/*** for interrupt with weak symbol in assembler ***/
#ifdef __cplusplus
extern "C" {
#endif /* __cplusplus */
void SysTick_Handler(void);
#ifdef __cplusplus
}
#endif /* __cplusplus */
/****************************************************/
void SysTick_Handler(void)
{
/* some code */
}
結果的にはたぶん、よくある「extern "C"問題」なわけですが、
シンボル解決が出来ないのではなく
シンボルが独立して存在しえたのが原因でした。
アセンブラ側のシンボルは「SysTick_Handler」
C++側のシンボルは「SysTick_Handler()」
と微妙に違うものがそれぞれ生成されていました。
それぞれは無関係なので割込みは発生しないという結果です。
「extern "C"」宣言でSysTick_Handler()をC言語(アセンブラ)側から
見えるように(SysTick_Handlerとして)することで解決しました。
*C言語で書かれたスタートアップコード
Cortex-M3は「スタートアップコードを全て"まるっと"C言語で書ける」というのが
売りだったりします。
実際「LPCXpresso」付属のものはそうなっています。
ごっそりいただこうと思いましたがライセンス上難しそうなので
フリーのものを探したらありました。
でも中身そっくりだったりします。(爆
このページの
stacks.h
startup_LPC17xx.c
.dataセクションに初期値をコピーするため
__RAM_MODE__が「0」になる様にしとくのが吉。
posted by Copyright (C) avrin All Rights Reserved. at 22:17|
Comment(3)
|
ARM系
|

|
もごもごもご。
まんぐるでまんぐる・・・。
割り込み関数を記述するにはweakな関数の
プロトタイプ宣言されたヘッダーが必要ですね。
逆に割り込み関数定義をC++名前空間に置かれた
りした日には、C言語で割り込み関数を記述で
きなくなりますので、致し方ありませんね。
まんぐるヒントありがとうございます。
言葉自体を知りませんでした。
少しだけ勉強してみます。(^^;
LPCXpressoはC++出来ないんです。orz
現在C++簡単プロジェクト作成中です。
ありがとうございます。