mbed LPC1768純正ボードのスタートアップルーチンを解析してみた

Toshio Kuga/ 2月 4, 2016/ 電子工作/ 0 comments

mbed only

mbedのスタートアップ処理はライブラリに組み込まれていて、隠蔽されとります。
普通に触ってたら、スタートアップ処理に触れる機会はありません!
「そんなの関係ねー!俺はどう動くか知っておきたいんやー!」という漢のために
mbed対応ボード LPC1768のスタートアップルーチンについて研究していくばい!

 

スポンサードリンク

Cortex-M3

LPC1768純正ボードのCPUはLPC1768で、そのコアは、Cortex-M3です。
ということで、まずはCortex-M3の基本的な動作をまとめます。

 

レジスタ

PC(プログラムカウンタ)

次に実行する命令のアドレスを格納するレジスタです。

CPUはPC(プログラムカウンタ)と呼ばれるレジスタから
命令をフェッチ(読み込み)して、デコード(解析)後にエグゼキュート(実行)します。

 

LR(リンクレジスタ)

サブルーチンコール時の戻り先を格納するレジスタです。

C言語のプログラムで書いた関数の呼び出しは、ブランチ命令にコンパイルされます。
ブランチ命令実行時にLR(リンクレジスタ)が書き換えられます。

 

SP(スタックポインタ)

スタックポインタはスタックの最上位アドレスを示します。
スタックとは、サブルーチンを実行する時に使用されるメモリ領域です。
ARMコアは引数は4つまでは汎用レジスタの中に入れることができますが
5つ以上はスタックを使用します。

 

CPUモード

Cortex-M3コアは、モードが2種類あります。

 

ハンドラモード

ハードウェア(ハンドラ)によって動作するモードです。
必ず特権アクセスとなります。

 

スレッドモード

ソフトウェアによって動作するモードです。
CONTROL[0]ビットをクリアすることで、特権から非特権アクセスに移ることができます。

 

スタック

Cortex-M3は、スタックが2つあります。

 

SP_main

ハンドラモードでは、常にSP_mainが使用されます。
スレッドモードで、使用するか選択可能です。

 

SP_process

スレッドモードで、使用するか選択可能です。
Control[1]で制御します。

 

例外発生時の動作

例外はメインルーチンとは別に実行することが要求される処理のことです。
割り込みやアボートなどがありますが、電源をオンした時も、リセット例外が発生します。

 

ハードウェア・ソフトウェア動作

Cortex-M3は、例外が発生すると以下のように動作します。

 

シーケンス 担当 モード
汎用レジスタを退避 HW
ベクタテーブルへ移動(PCをベクタテーブルにセット LRに戻りアドレスをセット) HW
ベクタテーブルに記載されているハンドラ処理のアドレスへジャンプ HW ハンドラモード遷移
例外処理 SW
復帰命令の実行 SW
汎用レジスタを復帰 HW
戻りアドレスに移動(PCをLRの格納アドレスにセット) HW スレッドモード遷移

 

ベクタ

Cortex-M3のベクタテーブルは0x0にあります。(移動も可能)
ベクタテーブルには、例外ハンドラのアドレスが格納されています。

ベクタテーブルはこんな感じです。

 

アドレス ベクタ
0x00 SP_mainの初期値
0x04 リセット
0x08 NMI
0x0C ハードフォールト
0x10 メモリ管理
0x14 バスフォールト
0x18 用法フォールト
0x1C-0x28 予約
0x30 SVC
0x34 デバッグモニター
0x38 予約
0x3C PendSV
0x40- IRQ

メモリマップ

Cortex-M3のメモリ領域は固定されています。
コードは0x0番地から0x1FFFFFFFの領域に格納されます。

 

スクリーンショット 2016-02-04 7.12.38

出典:Cortex-M3 Technical Reference Manual

 

LPC1768

ようやく、LPC1768の説明に入ります。(- -;)

 

メモリマップ

LPC1768のメモリマップはこんな感じどすえ。
コード領域の中は、512KBのFlash、32KBのRAM、8KBのROMがありますね。
ここの領域にはアクセスすることが可能です。

ベクタテーブルが0x0番地にあるようです。
GPIOは0x2009C000近辺にありますね。

 

スクリーンショット 2016-02-04 7.18.02出典:LPC176x/5x User manual

 

makeファイル

makeファイルを見ると、ビルド時に以下のようなオプションが指定されていました。

-nostdlib 標準Cライブラリを使わない

-L”XXXX” ディレクトリ探索

-Xlinker -Map=”mbed_lcd.map” 出力するMapファイルを指定 (Xilinkerはリンカオプションを指定)

-Xlinker –gc-sections 不要なセクションをガベージコレクションする (Xilinkerはリンカオプションを指定)

-mcpu=cortex-m3 コアを指定

-mthumb Thumb命令セットを使用することを要求

-T “XXXX/LPC1768.ld” リンカスクリプトを指定

-o “mbed_lcd.axf” 出力ファイル名を指定

 

リンカスクリプト

静的リンクライブラリの定義

リンカスクリプトが指定されているため
コンプラいる時に指定されている「LPC1768.ld」を見てみましょう。

リンクする静的ライブラリのオブジェクトファイルをGROUPキーワードで指定しています。

 

 

メモリ領域を定義

MEMORYキーワードでメモリ領域を定義します。

メモリ領域名称(メモリ属性):ORIGIN = 開始アドレス, LENTGH = サイズ
属性:r = 読出可, w = 書込可, x= 実行可

 

シンボルの定義

シンボルとはプログラムのアドレスと対になるソースコード上の名前のことです。
各メモリ領域の最後尾アドレスをここで定義しています。

 

エントリポイントの指定

エントリポイントとは、実行開始アドレスのことです。
ENTRYキーワードで、指定します。

 

セクションを定義

メモリはセクションという単位で扱われます。

セクション 説明
.text 命令が格納される領域
.data 0以外の初期値を持つグローバル変数
0以外の初期値を持つ静的局所変数
.bss 0の初期値を持つグローバル変数
0の初期値を持つ静的局所変数
初期値を持たないグローバル変数
初期値を持たない静的局所変数
.rodata 定数

 

セクション名:{} > メモリ領域名称 のフォーマットで指定します。
最初の定義では、メモリ領域 MFlash512をコード領域として定義しているようですねー。

 

.textセクションの中身です。

0xFFでフィルしているのは、書き込み回数の制限があり、
不要な書き込み回数を減らすためと思われます。
Flashメモリは初期値がオールFとなっています。

KEEPキーワードは、最適化で消されないために使用します。
例外ベクタテーブルは必ず必要なため、KEEPを指定しています。

 

textセクションの続きです。

.dataセクションは先ほどの表の通り、初期値を持つ変数です。
LOADADDR(転送元アドレス)、ADDR(転送先アドレス)、SIZEOF(サイズ)

bssセクションは初期値を持たない変数です。
RAM領域に配置され、0で初期化されます。
ADDR(アドレス)、SIZEOF(サイズ)

 

textセクションの続きです。
.after_vectorsセクションをまず配置するようにしています。
.after_vectorsセクションは、後述するスタートアップで定義されています。

 

.ARM.extabとARM.exidxはnewlibを使うときに必要みたいです。
newlibは、組込向けの小さなライブラリです。

グローバル変数を格納する.dataセクションと.bssセクションを定義しています。
ATは転送元を指定するキーワードでしょうか?

 

PROVIDEキーワードは、C言語の変数名とシンボル名で衝突が起きた時のためのものです。
C言語の変数名を優先し、定義されていない場合のみリンカスクリプトの宣言が有効となります。

Stackの初期値を指定しています。
Cortex-M3はSPの初期値は例外ベクタで指定します。

 

スタートアップルーチン

startup_LPC17xx.cppでスタートアップルーチンが記載されています。

 

WEAK          __attribute__ ((weak))

他で同名の関数が宣言された場合は、この宣言は無視される。
ハンドラー処理を定義していない場合もエラーとならないようにWEAK宣言を使っている。

WEAK宣言の関数をコールした場合は、分岐せずにNOP命令となる。

 

ALIAS(f)      __attribute__ ((weak, alias (#f)))

エイリアスとして関連づける。

 

AFTER_VECTORS __attribute__ ((section(“.after_vectors”)))

特別なセクションを指定しています。
ここで、リンカスクリプトで指定していた.after_vectorsセクションを指定していました。

g_pfnVectorsは関数ポイント配列の様です。

 

くがとしお 的まとめ

いやー、mbedはすぐに使用できるように色々抽象化されていますねー。
mbedを使用するときも、レジスタやメモリといった下回りまでイメージ
しながら電子工作したら、デバイスドライバ作成する仕事とかにも活用できていいかもしれませんね。

これからの時代は、この辺はブラックボックスと見なして
やりたい処理だけをコーディングする感じなんでしょうかね。

どちらもできるようになっておきたいですね。(^^)

 

参考

セクションについて
http://www.ertl.jp/~takayuki/readings/info/no02.html

newlibについて(日本の組み込み情報
http://www.embedded.jp/article/cross-4.html

Leave a Comment

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code class="" title="" data-url=""> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong> <pre class="" title="" data-url=""> <span class="" title="" data-url="">
*
*

日本語が含まれない投稿は無視されますのでご注意ください。(スパム対策)